C# 通用事件

标签 c# events generics

我有一个委托(delegate),其中一个参数是泛型类型:

public delegate void UpdatedPropertyDelegate<T>(
    RemoteClient callingClient, 
    ReplicableProperty<T> updatedProp, 
    ReplicableObject relevantObject
);

现在,我想要一个可以订阅供其他类使用的公共(public)事件。因此,我做了:

public event UpdatedPropertyDelegate<T> UpdatedProperty;

但是,编译器不喜欢那样。我不明白为什么必须在此处指定 T。当然,它是在我触发事件时指定的,即:

if (UpdatedProperty != null) 
{
    UpdatedProperty(this, readProperty, 
        ReplicableObjectBin.GetObjectByID(readProperty.OwnerID));
}

那么,我是不是做错了什么?或者这是理解的巨大失败?

谢谢。

最佳答案

听起来您需要的是接口(interface)类型,而不是委托(delegate)。接口(interface)方法可以接受开放的泛型类型(这就是您所追求的),即使委托(delegate)不能。例如,可以定义如下内容:

interface ActOnConstrainedThing<CT1,CT2>
{
  void Act<MainType>(MainType param) where MainType: CT1,CT2;
}

即使 CT1 的实现者和 CT2不要共享同样实现 CT1 的公共(public)基类型和 CT2 , Act 的实现可以将其传入参数用作 CT1CT2没有类型转换,甚至可以将它传递给需要带有 CT1 的通用参数的例程和 CT2约束。对于代表来说,这样的事情是不可能的。

请注意,使用接口(interface)而不是委托(delegate)意味着不能使用正常的“事件”机制和语法。相反,将成为事件发布者的对象必须维护一个实现所需接口(interface)的对象实例列表(例如 List<ActOnConstrainedThing<IThis,IThat>> ),并枚举该列表中的实例(可能使用 foreeach )。例如:

List<IActOnConstrainedThing<IThis,IThat>> _ActOnThingSubscribers;

void ActOnThings<T>(T param) where T:IThis,IThat
{
  foreach(var thing in _ActOnThingSubscribers)
  {
    thing.Act<T>(param);
  }
}

编辑/附录

我采用这种模式的地方还有一些其他的东西,这些东西似乎与问题不太相关,根据我的解释,这是在问一个人如何拥有一个带有开放类型参数的委托(delegate)(或等价物),以便调用委托(delegate)等价物的对象可以提供类型参数,而对象提供委托(delegate)不必事先知道。大多数情况下这是有用的涉及通用约束,但由于这显然会引起混淆,这里有一个没有的例子:

interface IShuffleFiveThings
{
  void Shuffle<T>(ref T p1, ref T p2, ref T p3, ref T p4, ref T p5);
}
List<IShuffleFiveThings _ShuffleSubscribers;

void ApplyShuffles<T>(ref T p1, ref T p2, ref T p3, ref T p4, ref T p5)
{
  foreach(var shuffler in _ShuffleSubscribers)
  {
    thing.Shuffle(ref p1, ref p2, ref p3, ref p4, ref p5);
  }
}

IShuffleFiveThings.Shuffle<T>方法通过 ref 接受五个参数并用它们做一些事情(很可能以某种方式排列它们;也许随机排列它们,或者随机排列一些而将其他的留在原处。如果一个人有一个列表 IShuffleFiveThings ,可以有效地使用该列表中的东西,无需装箱或反射,即可操纵任何类型的事物(包括类类型和值类型)。相比之下,如果使用委托(delegate):

delegate void ActOn5RefParameters(ref p1, ref p2, ref p3, ref p4, ref p5);

然后因为任何特定的委托(delegate)实例只能作用于其创建时提供的单个参数类型(除非它是一个仅通过反射调用的开放委托(delegate)),因此需要创建一个单独的委托(delegate)列表 对于希望打乱的每一种对象类型(是的,我知道通常会使用整数索引数组来处理排列;我选择排列作为一种操作,因为它适用于所有对象类型,而不是因为这种特殊的排列方法东西很有用)。

请注意,因为类型 TIShuffleFiveThings没有任何约束,除了类型转换(这可能会引入装箱)之外,实现将无法用它做很多事情。为这些参数添加约束会使它们更有用。虽然可以在接口(interface)内对此类约束进行硬编码,但这会限制接口(interface)对需要这些特定约束的应用程序的实用性。使约束本身具有通用性可以避免这种限制。

关于C# 通用事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10455147/

相关文章:

events - Saga Choreography实现问题

Java - 创建自定义事件和监听器

generics - 用于Rust中多个泛型转换的GADT

java - 如何创建通用子类的实例?出现错误 : "Bound mismatch: The type ... is not a valid substitute for the bounded parameter ..."

c# - Windows Phone 单元测试输出中的无助错误

c# - 使用自定义事件处理程序在表单之间传递数据

c# - 每秒触发一个事件

c# - 从始终匿名的对象中提取单个属性?

jQuery 结合焦点和悬停

generics - 向闭包添加显式返回会导致编译器错误: A compiler bug?