如何将Generic T转换为动作< ...>获得方法参数

时间:2013-01-25 08:38:08

标签: c# generics parameters action code-generation

您好我尝试将一个泛型强制转换为具有未知数量和类型的参数

的Action

目前它看起来像:

public class subscriber
{        
     public subscriber()
     {
        new Subscription<Action>(a);
        new Subscription<Action<string>>(b);
        new Subscription<Action<int,string>>(c);
     } 

     private void a() { }
     private void b(string gg){}
     private void c(int i, string g) { } 
}


public class Subscription<T>
{    
        public T MyAction {get {retun _action;}}
        public Type MyActionType {get;private set;}

        public Subscription( T action )
        {    
            MyAction  = action;
            MyActionType  = action.GetType();


        var gg = action.GetType().GetGenericArguments();// Contains the Sub generics
        }
}

目前我们知道它将是一个动作,我们也知道子类型但是如何把它们放在一起 执行我的private void c(int i, string g)方法

最终目标

是在Action移交某些参数时从Third-Class(包含List<Subscription>)执行Fourth-Class

2 个答案:

答案 0 :(得分:4)

public abstract class SubscriptionBase
{
    public abstract void ExecuteAction(params object[] parameters);
}

public class Subscription<T> : SubscriptionBase
{
    private T _action;

    public Subscription(T a)
    {
        _action = a;
    }

    public override void ExecuteAction(params object[] parameters)
    {
        (_action as Delegate).DynamicInvoke(parameters);
    }
}

你可以像使用它一样使用它;

Action<int> func1 = (q) => q += 1;
Action<int, int> func2 = (q, w) => q += w;

Subscription<Action<int>> s1 = new Subscription<Action<int>>(func1);
Subscription<Action<int, int>> s2 = new Subscription<Action<int, int>>(func2);

List<SubscriptionBase> subscriptionBase = new List<SubscriptionBase>();
subscriptionBase.Add(s1);
subscriptionBase.Add(s2);

subscriptionBase[1].ExecuteAction(1, 2);

答案 1 :(得分:1)

你不能这样做。您无法将Subscription<Action<int>>放入与Subscription<Action<string, Foo>>相同的列表中。

我建议您创建一个如下所示的界面并将其存储在您的第三个类中:

interface IActionExecutor
{
    bool CanExecuteForParameters(params object[] parameters);
    void Execute(params object[] parameters);
}

// Implementation for one parameter
// You need to create one class per additional parameter.
// This is similar to the Action delegates in the framework.
// You can probably extract a base class here that implements
// some of the repetitive pars
public class ActionExecutor<in T> : IActionExecutor
{
    private Action<T> _action;

    public ActionExecutor(Action<T> action)
    {
        if(action == null) throw new ArgumentNullException("action");
        _action = action;
    }

    public bool CanExecuteForParameters(params object[] parameters)
    {
        if(parameters == null) throw new ArgumentNullException("action");

        if(parameters.Length != 1) return false;
        return parameters[0] is T;
    }

    public void Execute(params object[] parameters)
    {
        if(parameters == null) throw new ArgumentNullException("action");
        if(parameters.Length != 1)
            throw new ArgumentOutOfRangeException("action");

        _action((T)parameters[0]);
    }
}

在第三节课中,您将获得IActionExecutor s的列表:

List<IActionExecutor> _subscriptions;

你会像这样使用它:

public void Execute(params object[] parameters)
{
    var matchingSubscriptions =
        _subscriptions.Where(x => x.CanExecuteForParameters(parameters);
    foreach(var subscription in matchingSubscriptions)
        subscription.Execute(parameters);
}

为了简化ActionExecutor实例的创建,您可以提供工厂类:

public static class ActionExecutor
{
    public IActionExecutor Create(Action action)
    {
        return new ActionExecutor(action);
    }

    public IActionExecutor Create<T>(Action<T> action)
    {
        return new ActionExecutor<T>(action);
    }

    public IActionExecutor Create<T1, T2>(Action<T1, T2> action)
    {
        return new ActionExecutor<T1, T2>(action);
    }

    // ... and so on
}

现在用法如下:

_subscriptions.Add(ActionExecutor.Create(a));
_subscriptions.Add(ActionExecutor.Create(b));
_subscriptions.Add(ActionExecutor.Create(c));