我如何动态地创建一个动作 在运行时?(How can I dynamically create

2019-07-31 04:47发布

我希望能够在运行时做等同于以下内容:

var action = new Action<ANYTHING AT RUNTIME>(obj => Console.WriteLine("Called = " + obj));

我知道我需要的正确类型的行动,但不知道如何使用Delegate.Create得到最终的位。 Type代表在行动定义吨。

var actionType = typeof(Action<>).MakeGenericType(Type);
var constructor = actionType.GetConstructors()[0];
var @delegate = Delegate.CreateDelegate(actionType, <WHAT GOES HERE>);

点人们似乎缺少的是我想创造一个T不能静态,因为它正在从属性派生的类使用指定的操作实例 - 此装置T可以是任何东西,它不能被定义为一般定义

干杯

Answer 1:

如果你知道你需要执行的,以及如何不论类型执行它(在你的例子)的操作,为什么不只是使执行操作的通用方法,并创建您的代理呀?

class Program
{
    public static void Perform<T>(T value)
    {
        Console.WriteLine("Called = " + value);
    }

    public static Delegate CreateAction(Type type)
    {
        var methodInfo = typeof (Program).GetMethod("Perform").MakeGenericMethod(type);
        var actionT = typeof (Action<>).MakeGenericType(type);
        return Delegate.CreateDelegate(actionT, methodInfo);
    }

    static void Main(string[] args)
    {
        CreateAction(typeof (int)).DynamicInvoke(5);
        Console.ReadLine();
    }
}


Answer 2:

您可以使用下面的代码,它的工作原理,如果类型可以铸造一个对象:

Action<object> func = o => Console.WriteLine("Called = " + o.GetType().Name);
var actionType = typeof(Action<>).MakeGenericType(type);
var constructor = actionType.GetConstructors()[0];
var @delegate = Delegate.CreateDelegate(actionType, func.Method);

然而,如果类型是枚举,否则将无法正常工作等价值型。



Answer 3:

感谢“@prashanth”建议,我管理动态创建和调用一个动作<>与运行时类型得益于动态关键字:

        public Action<dynamic> GetDynamicAction(/* some params */)
        {
            return oDyn =>
            {
                //here is the action code with the use of /* some params */
            };
        }

例如,用基本动作的处理程序:

public class ActionHandler
{
     public ReturnType DoAction<T>(Action<T> t)
     {
         //whatever needed
     }
}

使用案例:

/* some params */ = Any runtime type specific data (in my case I had a Type and a MethodInfo passed as parameters and that were called in the action)

var genericMethod = actionHandler.GetType().GetMethod(nameof(ActionHandler.DoAction));
var method = genericMethod.MakeGenericMethod(runtimeGenericType);

var actionResult = (ReturnType) method.Invoke(actionHandler, new object[]
                    {
                        GetDynamicAction(/*some params*/)
                    }
                );



Answer 4:

简短的答案是创建一个委托MyActionDelegate ,然后使用:

delegate void MyActionDelegate(T arg);
Delegate @delegate = new MyActionDelegate((a) => Console.WriteLine(a));

下面是一个使用泛型类的工作示例:

public class MyClass<T>
{
    public delegate void ActionDelegate(T arg);

    public void RunGenericAction(T arg)
    {
        var actionType = typeof(Action<>).MakeGenericType(typeof(T));
        var constructor = actionType.GetConstructors()[0];
        Delegate @delegate = new ActionDelegate((a) => { Console.WriteLine(arg); });
        var inst = (Action<T>)constructor.Invoke(new object[] { 
            @delegate.Target,  
            @delegate.Method.MethodHandle.GetFunctionPointer() 
        });
        inst(arg);
    }
}

这样使用它,它输出123到控制台:

var c = new MyClass<int>();
c.RunGenericAction(123);

你会注意到我传递两个参数Constructor.Invoke ; 这是因为事实证明,委托说法实际上编译为两个参数:该函数的目标对象和函数指针。 我不能把信贷的花式步法有; “借用”从信息如何通过使用反射委托论证这个优秀的答案。



Answer 5:

使用下面的代码来创建一个委托,这是在型号参数后期绑定。 另请参阅如何:检查和实例化泛型类型与反思 。

abstract class ActionHelper {

    protected abstract Delegate CreateActionImpl();

    // A subclass with a static type parameter
    private class ActionHelper<T> : ActionHelper {
        protected override Delegate CreateActionImpl() {
            // create an Action<T> and downcast
            return new Action<T>(obj => Console.WriteLine("Called = " + (object)obj));
        }
    }

    public static Delegate CreateAction(Type type) {
        // create the type-specific type of the helper
        var helperType = typeof(ActionHelper<>).MakeGenericType(type);
        // create an instance of the helper
        // and upcast to base class
        var helper = (ActionHelper)Activator.CreateInstance(helperType);
        // call base method
        return helper.CreateActionImpl();
    }
}

// Usage
// Note: The "var" is always "Delegate"
var @delegate = ActionHelper.CreateAction(anyTypeAtRuntime);

这就是说,我不建议使用这种方法。 相反,使用

Action<object> action = obj => Console.WriteLine("Called = " + obj);

它提供

  • 同样的功能。

    原密码"Called = " + obj"要求.ToString()的参数,所以请问以上。

  • 没有性能上的差异。

    如果obj参数是一个值类型,这两种变型进行装箱操作。 在首先进行的拳击并不明显,但"Called = " + obj"框中的值类型。

  • 短,不易出错。



文章来源: How can I dynamically create an Action at runtime?