为类的所有方法订阅委托
本文关键字:有方法 | 更新日期: 2023-09-27 18:01:35
我只是稍微熟悉了一下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;
}
}
编辑:罗林的解决方案是我最喜欢的。它简单明了。作为一个小调整,我尝试了如何处理动态类型的对象,它确实有效:控制器和受控对象之间完全解耦。当然,这种"动态"的用法并不是每个人都喜欢的……
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());
现在我意识到这实际上是在再造备受诟病的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()));
如果你想要调用实际的方法和智能感知,你需要研究代码生成——这是可能的,但我怀疑它是否值得这么麻烦。
我想这应该行得通:
//编辑:不要简化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;
}