How would you go about using reflection to execute the following method when the type can only be inferred at runtime?
MainObject.TheMethod<T>(Action<OtherObject<T>>)
in everyday use, typically:
mainObject.Method<Message>(m => m.Do("Something"))
So, given a list of types, I need to substitute them for T in the method above and invoke.
This is where I got before my head to turned to putty:
var mapped = typeof(Action<OtherObject<>>).MakeGenericType(t.GetType());
Activator.CreateInstance(mapped, new object[] { erm do something?});
typeof(OtherObject)
.GetMethod("TheMethod")
.MakeGenericMethod(t.GetType())
.Invoke(model, new object[] { new mapped(m => m.Do("Something")) });
Update: For clarification, i have a list of types and i wish to execute the same known method of OtherObject for each. Pseudo-code:
foreach(var t in types)
{
mainObject.TheMethod<t>(mo => mo.Do("Something"))
}
(The type of the parameter for TheMethod() is Action<OtherObject<T>>
as stated above)
FluentNHibernate.Automapping.AutoPersistenceModel Override<T>(System.Action<AutoMapping<T>> populateMap)
the action is the same of AutoMapping<T>.Where("something")
model.Override<Message>(m => m.Where("DeletedById is null"))
Now, do that for a bunch of types :)
Calling a generic method with a type parameter known only at runtime can be greatly simplified by using a dynamic type instead of the reflection API. To use this technique the type must be known from the actual object (not just an instance of the Type class).
While defining a generic method you need to specify the type parameter within the angle brackets (< T >). This should be placed before the method's return type.
You can solve this by using expressions:
foreach(var t in types)
{
var mapped = typeof(AutoMapping<>).MakeGenericType(t);
var p = Expression.Parameter(mapped, "m");
var expression = Expression.Lambda(Expression.GetActionType(mapped),
Expression.Call(p, mapped.GetMethod("Do"),
Expression.Constant("Something")), p);
typeof(SomeOtherObject).GetMethod("TheMethod").MakeGenericMethod(t)
.Invoke(model, new object[] { expression.Compile() });
}
UPDATE: Complete working example (paste into LINQPad and run it):
void Main()
{
var types = new []{typeof(string), typeof(Guid)};
SomeOtherObject model = new SomeOtherObject();
foreach(var t in types)
{
var mapped = typeof(AutoMapping<>).MakeGenericType(t);
var p = Expression.Parameter(mapped, "m");
var expression = Expression.Lambda(
Expression.GetActionType(mapped),
Expression.Call(p, mapped.GetMethod("Do"),
Expression.Constant("Something")), p);
typeof(SomeOtherObject).GetMethod("TheMethod")
.MakeGenericMethod(t)
.Invoke(model,
new object[] { expression.Compile() });
}
}
class AutoMapping<T>
{
public void Do(string p)
{
Console.WriteLine(typeof(T).ToString());
Console.WriteLine(p);
}
}
class SomeOtherObject
{
public void TheMethod<T>(Action<AutoMapping<T>> action)
{
var x = new AutoMapping<T>();
action(x);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With