10

No doubt elements of this question have been asked before, but I'm having trouble finding an answer. (Disclaimer: this is related, but separate from a recent question I asked).

I have a method like this:

public static void Method<T>(MethodInfo m, T value) { Type memberType = m.GetValueType(); if (memberType.IsAssignableFrom(typeof(List<T>)) { object memberValue = Activator.CreateInstance(memberType); ((List<T>)memberValue).Add(value); } } 

This works fine when I call it like this:

string s = "blah"; Method(memberInfo, s); 

However, I need to call this method using a generic type, so I'm calling it like this:

Type valueType = someType; object passValue = someMethod.MakeGenericMethod(new Type[] { valueType }).Invoke(this, new object[] { }); /* Call my original method */ Method(memberInfo, passValue ); 

Now, intellisense knows that 'value' in Method<T> is whatever type valueType is (say 'FooObject'). But 'T' is object, which means that a List<FooObject> is not assignable from a List<T> (i.e. a List<object>).

I've tried using Convert.ChangeType on the variable ('passValue') beforehand but that wasn't any more useful.

As there is no way to cast a variable to the Type of a type variable, how do I get around this?

Is the best solution to somehow not rely on IsAssignableFrom and do a looser type check of whether this will work? The problem with this is that I'm not sure I'll be able to cast the memberValue properly unless 'T' is truly the element type of memberValue.

2
  • GetValueType() is an extension method in your code. But even without seeing its code, it appears the method Method<T> doesn't do... anything? I'd like to give you an improved solution but I really can't figure out what you're trying to do here. Commented Sep 3, 2009 at 4:55
  • Yeah sorry getvaluetype is just a method to call FieldType/PropertyType for a given MemberInfo depending on the particular MemberType. Method<T> appends an object to a MemberInfo that represents a list (i.e .a Field or Property that is a List) Commented Sep 3, 2009 at 6:53

2 Answers 2

6

You're in luck. I actually had to do something very similar a few weeks ago.

For a detailed explanation see the above blog post, but basically the general idea is to reflect the type and manually invoke the method with an explicit set of parameters.

typeof(MyClass).GetMethod("Foo").MakeGenericMethod(new[] { param.GetType() }).Invoke(null, new[] { param }); 

It's not very type safe, but it does exactly what you're looking for.

class Program { static void Main(string[] args) { object str = "Hello World"; object num = 5; object obj = new object(); Console.WriteLine("var\tvalue\t\tFoo() Type\tCallFoo() Type"); Console.WriteLine("-------------------------------------------------------"); Console.WriteLine("{0}\t{1}\t{2}\t{3}", "str", str, MyClass.Foo(str), MyClass.CallFoo(str)); Console.WriteLine("{0}\t{1}\t\t{2}\t{3}", "num", num, MyClass.Foo(num), MyClass.CallFoo(num)); Console.WriteLine("{0}\t{1}\t{2}\t{3}", "obj", obj, MyClass.Foo(obj), MyClass.CallFoo(obj)); } } class MyClass { public static Type Foo<T>(T param) { return typeof(T); } public static Type CallFoo(object param) { return (Type)typeof(MyClass).GetMethod("Foo").MakeGenericMethod(new[] { param.GetType() }).Invoke(null, new[] { param }); } } 

Output

 var value Foo() Type CallFoo() Type ------------------------------------------------------- str Hello World System.Object System.String num 5 System.Object System.Int32 obj System.Object System.Object System.Object 
Sign up to request clarification or add additional context in comments.

1 Comment

That took me longer than I care to admit and I'm glad I could save you the time! Happy Coding :)
6

This should give you a callable method (I'll test it in a little while). The boxing/unboxing it incurs is much faster than the security checks required for the Reflection API invocation (which happens to also require boxing).

private static Action<MethodInfo, object> BuildAccessor(Type valueType) { MethodInfo genericMethod = null; // <-- fill this in MethodInfo method = genericMethod.MakeGenericMethod(new Type[] { valueType }); ParameterExpression methodInfo = Expression.Parameter(typeof(MethodInfo), "methodInfo"); ParameterExpression obj = Expression.Parameter(typeof(object), "obj"); Expression<Action<MethodInfo, object>> expr = Expression.Lambda<Action<MethodInfo, object>>( Expression.Call(method, methodInfo, Expression.Convert(obj, valueType)), methodInfo, obj); return expr.Compile(); } 

3 Comments

Looks like this should work too :-) Thanks! It seems to come down to calling the generic method dynamically in order to cast the type right.
Can you demonstrate this? I'm a little unsure how it needs to be called.
Well like you are calling the method dynamically rather than directly in order for the type to resolve itself. I just imagined this was doing something similar.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.