你如何动态地推断Action <t>的类型?</t>

时间:2013-10-15 14:58:29

标签: c# generics

我有一本字典如下:

var composEvents = new Dictionary<Type, Delegate>
{
    { 
        typeof (GetWorkflowAnalysisDealLevelViewDataCompletedEvent),
        new Action<bool>(GetWorkflowAnalysisDealLevelViewDataCompleted)
    },{
        typeof (NoDataReturnedEvent), 
        new Action<NoDataReturnedParameters>(NoDataReturned)
    }
};

然后我订阅了不同的事件,将这些操作作为回调传递,但每个事件的每个操作的类型都不同,即:

 Action<bool>
 Action<NoDataReturnedParameters>

如何动态生成以下代码而不显式转换操作类型?

foreach (var cEvent in composEvents)
{
    var method = typeof(IEventAggregator).GetMethod("GetEvent", BindingFlags.Public | BindingFlags.Instance);
    var generic = method.MakeGenericMethod(cEvent.Key);
    dynamic evt = generic.Invoke(_eventAggregator, null);
    var cancelationToken = evt.Subscribe((Action<bool>)cEvent.Value);
    _compositeEvents.Add(evt, cancelationToken);
}

2 个答案:

答案 0 :(得分:1)

我相信以下内容将达到您的预期结果:

public abstract class Base 
{
    public abstract void Assign ( object value );
}

public class Assigner<EventType, ActionType>: Base
{
    public override void Assign ( object value )
    {
        AssignAction((ActionType)value);
    }

    private void AssignAction ( ActionType action )  
    {
        var event = _eventAggregator.GetEvent<EventType>();
        var token = event.Subscribe(action);
        _compositeEvents.Add(event, token);
    }
}

其他地方:

foreach (var cEvent in composEvents)
{
    var genericType = typeof(Assigner<,>).MakeGenericType(cEvent.Key, cEvent.Value.GetType());
    var assignerInstance = (Base)Activator.CreateInstance(genericType);
    assignerInstance.Assign(cEvent.Value);
}

请注意我在这里直接键入了所有代码,因此可能存在语法错误,拼写错误和意外误导。

我相信如果不这样做会有效:请随时告诉我。

Assigner类型正在使用它无权访问的_compositeEvents和_eventAggregator(最有可能),因此您需要将它们传递给构造函数或从某个地方访问它们。

您需要为泛型类型参数添加一些约束,因为GetEvent()有它们,但希望这些约束相对明显。

答案 1 :(得分:0)

所以你有一个Action<T>,你需要把它变成Action<object>。为了做到这一点,如果对象的类型T不合适,该方法必然会在运行时失败。没有真正的方法。您可以使用DynamicInvoke尝试使用给定对象调用委托。如果它是正确的类型它将起作用,如果不是,它将不会:

public static Action<object> Foo(Delegate del)
{
    return obj => del.DynamicInvoke(obj);
}