简体   繁体   中英

How to activate a generic method that takes an action as its parameter

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 :)

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);
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM