创建泛型类型的Action<>;在运行时

本文关键字:运行时 gt lt Action 创建 泛型类型 | 更新日期: 2023-09-27 18:00:26

是否可以在运行时基于某些指定类型创建泛型类型的Action?在这种特殊情况下,Action的主体最终将忽略参数类型,因为类型化的Action<>将只是一个无参数操作的包装,例如

Action original = () => { };
...
Action<TType> wrapper = (arg) => {
    original();
}

或者,甚至:

Action<TTypeA, TTypeB> wrapper = (arg) => {
    original();
}

正如您所看到的,类型化Action<>的主体忽略参数及其类型,它只是充当一个包装器。

如果你想知道我为什么首先要创建这个包装器,"基本"版本是我最终将Action转换为Delegate.Combine(),这需要相同的类型。我试图用Delegate.Combine()完成的只是一个基本的通知,即该委托已被解雇。

在这一点上,我可能会重新设计以避免这些类型的恶作剧,但我仍然很好奇如何实现这一点。

我能得到的最接近的是:

private static TType GetTypedDelegate<TType>(Action onComplete)
        where TType : class
    {
        MethodInfo info = typeof(TType).GetMethod("Invoke");
        ParameterInfo[] parameters = info.GetParameters();
        object result;
        if (parameters.Length == 0)
            result = onComplete;
        else if (parameters.Length == 1)
            result = GetTypedDelegate<TType>(onComplete, parameters[0].ParameterType);
        // etc
        TType onCompleteCasted = Delegate.CreateDelegate(typeof(TType), result, "Invoke") as TType;
        return onCompleteCasted;
    }
    private static Delegate GetTypedDelegate<TType>(Action onComplete, Type type)
    {
        // This line isn't useful for me right now, since I can't just create a new
        // instance of the action with a parameterless constructor ... but I thought I'd throw it in here in case it was of use
        Type actionType = typeof(Action<>).MakeGenericType(new[] { type });
        // Do some magic here with the type information
        // The following of course does not work,but you get the idea of what I am aiming for
        Action<type> wrapper = (arg1) =>
        {
            onComplete();
        };
        return wrapper as Delegate;
    }

创建泛型类型的Action<>;在运行时

我认为最简单的选择是编写一个通用方法,然后动态调用它(使用反射,甚至可能使用C#4 dynamic):

class Helper {
  public static Action<TType> Wrap1<TType>(Action arg) {
    return (arg) => { original(); }
  }
}

使用Reflection调用方法并使用typ1作为泛型类型参数可能如下所示:

var meth = typeof(Helper).GetMethod("Wrap1");
var gmeth = meth.MakeGenericMethod(new[] { typ1 });
var genericAction = gmeth.Invoke(null, new object[] { action });

如果你不想使用反射,你可以像这样设置一些类。

public class ActionWrapper<TTypeA>
{
    protected readonly Action _original;
    public ActionWrapper(Action original)
    {
        _original = original;
    }
    public Action<TTypeA> Wrapped { get { return WrappedAction; } }
    private void WrappedAction(TTypeA a)
    {
        _original();
    }
}
public class ActionWrapper<TTypeA,TTypeB>:ActionWrapper<TTypeA>
{
    public ActionWrapper(Action original) : base(original)
    {
    }
    public new Action<TTypeA, TTypeB> Wrapped { get { return WrappedAction; } }
    private void WrappedAction(TTypeA a,TTypeB b)
    {
        _original();
    }
}