Please see Andras Zoltan's answer for an explanation of what you are doing wrong However, if you use . NET 4.0, you don't need to use reflection to call the method, you can simply use the new dynamic keyword: var currentContext = new AuthContext(); var dbSets = typeof(AuthContext). GetProperties(BindingFlags.
Public | BindingFlags. Instance); dbSets. Where(pi => pi.PropertyType.
IsGenericTypeDefinition && pi.PropertyType. GetGenericTypeDefinition() == typeof(DbSet)) .ToList() . ForEach(pi => ExtensionClass.
Clear((dynamic)pi. GetValue(currentContext, null))) I changed the cast from DbSet.
Please see Andras Zoltan's answer for an explanation of what you are doing wrong. However, if you use . NET 4.0, you don't need to use reflection to call the method, you can simply use the new dynamic keyword: var currentContext = new AuthContext(); var dbSets = typeof(AuthContext).
GetProperties(BindingFlags. Public | BindingFlags. Instance); dbSets.
Where(pi => pi.PropertyType. IsGenericTypeDefinition && pi.PropertyType. GetGenericTypeDefinition() == typeof(DbSet)) .ToList() .
ForEach(pi => ExtensionClass. Clear((dynamic)pi. GetValue(currentContext, null))); I changed the cast from DbSet to dynamic and changed the way the method is called.
Because Clear is an extension method, it can't be called directly on the dynamic type, because dynamic doesn't know about extension methods. But as extension methods are not much more than static methods, you can always change a call to an extension method to a normal call to the static method. Everything you have to do is to change ExtensionClass to the real class name in which Clear is defined.
Running a quick redux of the code I get Microsoft.CSharp.RuntimeBinder. RuntimeBinderException: 'Tests. A' does not contain a definition for 'Clear'.
It certainly would work for an instance method. You also couldn't invoke the extension explicitly as a static either, because presumably it's Clear and needs a generic argument. Actually, perhaps we need the method declaration from the OP – Andras Zoltan Jun 10 at 10:33 @Andras: Ah... I missed that.
Corrected. – Daniel lgarth Jun 10 at 10:34 @Daniel I then edited my comment (that never works does it!); this won't work if the OP's method is Clear - which I'm guessing it must be if it works on any DbSet (in the absence of a base class! ) – Andras Zoltan Jun 10 at 10:37 @Andras: Hm, did I miss that, too?
Let me check... – Daniel lgarth Jun 10 at 10:38 @Daniel - I don't think you did actually - it's compiling and running here; now that is cool; I never thought dynamic dispatch extended to cracking out the correct generic parameters for a method... +100 – Andras Zoltan Jun 10 at 10:39.
Your cast is wrong. You can't cast to (DbSet) because that's not a concrete type unless T is defined inside a generic method or generic type. You have a couple of possibilities.
If DbSet has a base class (e.g. DbSet_BaseClass in my code below) from which you can still implement your Clear() method - then change it's signature from: public static void Clear(this DbSet) to: public static void Clear(this DbSet_BaseClass) Then you can change your cast in the . ForEach to ((DbSet_BaseClass)pi.GetValue... If you can't do that, you could reflect-invoke the Clear extension method by building a specific generic version of it for the T of the DbSet: MethodInfo myClearMethod = typeof(container_type). GetMethod( "Clear", BindingFlags.
Public | BindingFlags. Static); Then, given a property info and context instance: Type propType = pi. PropertyType; Type typeofT = propType.
GetGenericArguments0; MethodInfo toInvoke = myClearMethod. MakeGenericMethod(typeofT); //now invoke it toInvoke. Invoke(null, new { pi.
GetValue(currentContext, null) }); There are lots of optimisations you can put on top of this, caching delegates etc etc, but this will work. Update Or see @Daniel lgarth's answer for a cool way to dynamically dispatch the call to the extension method without having to do any of the above (dynamic dispatch effectively does something like the above, but for you with all the caching on top). If it were me - I'd be using that.
1 One optimization would be to use dynamic. You might want to add a sample of that. – Daniel lgarth Jun 10 at 10:09 @Daniel I still think in DIY dynamic binding sometimes :) – Andras Zoltan Jun 10 at 10:11 @Daniel fancy putting up another solution for how you see dynamic working?
I've had a thought about the dynamic case, but can't easily see a nice way to convert from extnMethod(this A) to dynamic that doesn't end up requiring reflection in the extension method! I'm missing something I think – Andras Zoltan Jun 10 at 10:18 Have a look at my answer. This should do it.
– Daniel lgarth Jun 10 at 10:27 I was also thinking about the creating the non-generic version public static void Clear(this DbSet set), but then the line . ForEach(pi = ((DbSet)pi. GetValue(currentContext, null)).Clear()); gives me Invalid Cast Exception (cannot cast DbSet to DbSet).
However this line is working: DbSet testCastEmp = (DbSet) currentContext.Employees. Am I missing something? – michal.
Kohut Jun 10 at 12:58.
You can't cast the types because they've got no relationship to each other. You're getting a PropertyInfo which tells you about the type, but is not the type itself. I think you're going to want to use Type.
GetMethod to locate the "Clear" method, as a MethodInfo, and then you'll be able to call MethodInfo.Invoke.
2 he's getting the instance from the PropertyInfo using GetValue – Andras Zoltan Jun 10 at 9:58 1 This is not the problem as he is not trying to cast pi but the result of pi.GetValue. (@Andras: I know you said the same thing, but I wanted to re-phrase it, because I didn't understand your comment at first... ;-)) – Daniel lgarth Jun 10 at 10:01 @Daniel lgarth - no problem at all :) – Andras Zoltan Jun 10 at 10:07.
You have to do reflection on the DbSet to invoke the Clear Method Try this : var dbSets = typeof(AuthContext). GetProperties(BindingFlags. Public | BindingFlags.
Instance); dbSets. Where(pi => pi.PropertyType. IsGenericType && pi.PropertyType.
GetGenericTypeDefinition() == typeof(DbSet)).ToList() . ForEach(pi => { typeof(DbSet) . MakeGenericType(pi.PropertyType.
GetGenericArguments()0) . GetMethod("Clear") . Invoke(pi.
GetValue(currentContext, null), null); } ).
It's an extension method so he can't retrieve it off the DbSet type and . Invoke it – Andras Zoltan Jun 10 at 10:20.
Your cast is wrong. You can't cast to (DbSet) because that's not a concrete type unless T is defined inside a generic method or generic type. You have a couple of possibilities.
If DbSet has a base class (e.g. Then you can change your cast in the . There are lots of optimisations you can put on top of this, caching delegates etc etc, but this will work. Or see @Daniel Hilgarth's answer for a cool way to dynamically dispatch the call to the extension method without having to do any of the above (dynamic dispatch effectively does something like the above, but for you with all the caching on top).
Unfortunately, you cannot create constraints of the type of describe. You cannot write, for example: class MyClass where T : int { ... } // won't compile You may be better off leaving the constraint to be struct but add some runtime checks to make sure that T is only one of the supported types when you instantiate the class. Since you haven't said much how you're planning to use your class - it's hard to offer alternative design advice on how to achieve better type safety EDIT: You should look at the type converter option that Marc and others recommend.
This seems like the way to go EDIT: One possible idea that occurs to me, is to make the Parse() method actually be a delegate: Func int. Parse( s ); public static Func ParseFloat = s => float. Parse(s); } You can read about the available constraints here The only constraints available are: struct (optional) new() (optional) interface constraint (optional, multiple allows) base class constraint (optional, only one allowed) naked constraints ( such as where T : TResult ).
Unfortunately, you cannot create constraints of the type of describe. You cannot write, for example: class MyClass where T : int { ... } // won't compile You may be better off leaving the constraint to be struct, but add some runtime checks to make sure that T is only one of the supported types when you instantiate the class. Since you haven't said much how you're planning to use your class - it's hard to offer alternative design advice on how to achieve better type safety.
EDIT: You should look at the type converter option that Marc and others recommend. This seems like the way to go. EDIT: One possible idea that occurs to me, is to make the Parse() method actually be a delegate: Func - that you assign during construction.
This would make it possible for you to: Avoid the inefficient and awkward if/else logic. Improve the future use of your class to other value types (structs, BigDecimal, etc) Here's a code example of what I mean: class MyClass { private readonly Func ParseEntry; public MyClass( Func parser ) { ParseEntry = parser; } } public static class AvailableParsers { public static Func ParseInt = s => int. Parse( s ); public static Func ParseFloat = s => float.
Parse(s); } You can read about the available constraints here. The only constraints available are: struct (optional) new() (optional) interface constraint (optional, multiple allows) base class constraint (optional, only one allowed) naked constraints ( such as where T : TResult ).
Now I'm wondering... does the CLR allow System. Int32 as a constraint? Can we do that with the same trick Jon Skeet using on Unconstrained Melody?
– R. Martinho Fernandes Jan 8 '10 at 22:23 @Martinho: No you can't. And what would be the point?
A method signature like MyFunc(T num) where T : int would be effectively the same as MyFunc(int num). – LukeH Jan 9 '10 at 0:29 Delegate solution seemed to be the simpliest. The constructor is internal to the library (i.e.
User's have access to created objects but can't create them) so passing the extra argument is no big deal. – Brian Triplett Jan 11 '10 at 21:00.
Private static T ParseEntry(string entry) { TypeConverter conv = TypeDescriptor. GetConverter(typeof(T)); return (T) conv. ConvertFromString(entry); } which has the advantage of working with any type with a type-converter (or you can add your own at runtime).
It does have boxing, but really, it isn't so bad. If that is your biggest problem, then you're going about this the wrong way.
I ran the above code versus just calling the Parse method and I found it to be a full 5x slower. Not sure if would agree with Skeet's blog that boxing is "in the noise". I agree that you shouldn't jump through design hoops to avoid it but it should be avoided if possible.
– Brian Triplett Jan 11 '10 at 20:52.
Edit: Thinking about the usage I think you might actually want to use Convert.ChangeType. Something like this: class MyClass where T: IConvertible { private static T ParseEntry(string entry) { return (T)Convert. ChangeType(entry, typeof(T)); } }.
Like Mr. Bushkin said, you can't do that. So you're other option would be to simply make several overloads of the method for each primitive type. Also, imagine that you didn't have to deal with primitive types, but you really wanted to handle all structs - it still wouldn't be possible, since the struct is not guaranteed to implement an (heretofore imaginary) interface called IParsable to be cast into T.
I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.