订阅代表所有类的方法

时间:2013-02-28 07:47:08

标签: c#

我刚刚对C#代表进行了一些熟悉。可以通过“+ =”运算符将多个委托实例订阅给委托。但是,是否有可能有一个控制器类,它具有第二类中所有方法的委托,并且自动添加方法,即无需将每个方法单独添加(甚至知道)给相应的委托?

在简化代码中(省略访问修饰符等):

class Car
{
    void Start();
    void Drive();
}

// I would like to have the following class generated automatically
// without needing to repeat all the methods of Car, i.e.
// without declaring a delegate instance for each of them
class CarController
{
    delegate void DoSomething();

    DoSomething StartAll;
    DoSomething DriveAll;

    void Subscribe(Car anotherCar)
    {
        StartAll += anotherCar.Start;
        DriveAll += anotherCar.Drive;
    }
}

编辑: 罗林的解决方案是我最喜欢的解决方案。它简单明了。作为一个小小的调整我已经尝试过这个东西如何与动态类型对象一起工作,它确实有效:在Controller和受控对象之间完全解耦。当然,这种“动态”的使用并不是每个人的口味......

public class CallAller2 : HashSet<dynamic>
{
    public void CallAll(Action<dynamic> action)
    {
        foreach (dynamic t in this)
        {
            try {action(t);} catch (RuntimeBinderException) {};
        }
    }
}

class Bike
{
    void Drive();
}

CallAller2 ca = new CallAller2();
ca.Add(new Car());
ca.Add(new Bike());
ca.CallAll(c => c.Start());  // is ignored by Bike which does not implement it  
ca.CallAll(c => c.Drive());

2 个答案:

答案 0 :(得分:0)

我认为这应该有效:

//编辑:不要简化MethodInfo mi1 = mi,否则会出现一个名为Access to modified closure的问题

    static IList<Action> getDelegatesFromObject(Object obj)
    {
        Type type = obj.GetType();

        List<Action> Actions = new List<Action>();
        foreach (MethodInfo mi in type.GetMethods())
        {
            MethodInfo mi1 = mi;

            Actions.Add(
                () => mi1.Invoke(obj, new object[] {})
            );
        }

        return Actions;
    }

答案 1 :(得分:0)

现在我意识到这只是在重新创建备受诟病的List<T>.ForEach。为什么不使用它,因为它在那里?


虽然它不能让您只是致电.StartAll.DriveAll,但您可以做一些简单的事情

class CallAller<T> : HashSet<T>
{
    public void CallAll(Action<T> action)
    {
        foreach (T t in this)
        {
            action(t);
        }
    }
}

var ca = new CallAller<Car>();
ca.Add(myFirstCar);
ca.Add(mySecondCar);

// Call a simple function
ca.CallAll(c => c.Start());

// Call a function taking parameters
ca.CallAll(c => c.SetRadio(88.1, RadioType.FM));

// Get return values... if you really need to.
Dictionary<Car, int> returnValues = new Dictionary<Car, int>();
ca.CallAll(c => returnValues.Add(c, c.GetNumberOfTyres()));

如果你想要使用实际方法来调用和智能感知,你需要研究代码生成 - 这是可能的,但我怀疑这是值得的麻烦。