4

嗨,我正在尝试将泛型转换为具有未知数量和类型的参数的动作

目前它看起来像:

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)方法

最终目标

是在交出一些参数时执行Actionfrom a Third-Class(其中将包含 a List<Subscription>Fourth-Class

4

2 回答 2

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);
于 2013-01-25T08:54:10.397 回答
1

你不能那样做。您不能将 aSubscription<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]);
    }
}

在您的第三堂课中,您将拥有IActionExecutors 的列表:

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));
于 2013-01-25T08:45:26.210 回答