Xen*_*ate 8 c# generics events
我有一个委托与泛型类型作为参数之一:
public delegate void UpdatedPropertyDelegate<T>(
RemoteClient callingClient,
ReplicableProperty<T> updatedProp,
ReplicableObject relevantObject
);
Run Code Online (Sandbox Code Playgroud)
现在,我想要一个可以订阅的公共事件供其他类使用.因此,我做了:
public event UpdatedPropertyDelegate<T> UpdatedProperty;
Run Code Online (Sandbox Code Playgroud)
但是,编译器不喜欢这样.我不明白为什么必须在这里指定T. 当然,它是在我发射事件时指定的,即:
if (UpdatedProperty != null)
{
UpdatedProperty(this, readProperty,
ReplicableObjectBin.GetObjectByID(readProperty.OwnerID));
}
Run Code Online (Sandbox Code Playgroud)
那么,我做了一些简单的错误吗?或者这是一次大规模的理解失败?
谢谢.
听起来你需要的是接口类型,而不是委托.接口方法可以接受开放的泛型类型(这就是你所追求的),即使代理不能.例如,可以定义如下内容:
interface ActOnConstrainedThing<CT1,CT2>
{
void Act<MainType>(MainType param) where MainType: CT1,CT2;
}
Run Code Online (Sandbox Code Playgroud)
即使实施者CT1和CT2不共享这也实现了一个共同的基本类型CT1和CT2,的实现Act可以使用其传入的参数作为CT1或CT2不强制类型转换,甚至可以把它作为其期望与通用参数,程序CT1和CT2限制.代表们无法做到这样的事情.
请注意,使用接口而不是委托意味着不能使用正常的"事件"机制和语法.相反,作为事件发布者的对象必须维护实现所需接口(例如a 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);
}
}
编辑/编
我使用这种模式的地方还有一些其他东西似乎与这个问题不太相关,我的解释是询问如何使用open类型参数获得委托(或等效),以便调用对象委托等价物可以提供类型参数,而没有提供委托的对象必须事先知道它.大多数情况下这是有用的涉及泛型约束,但由于这显然引入了混淆,这里的示例不是:
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 void ActOn5RefParameters(ref p1, ref p2, ref p3, ref p4, ref p5);
那么因为任何特定的委托实例只能对其创建时提供的单个参数类型起作用(除非它是一个只通过Reflection调用的开放委托),否则需要为每个希望的对象类型创建一个单独的委托列表. shuffle(是的,我知道通常会通过使用整数索引数组来处理排列;我选择排列作为操作,因为它适用于所有对象类型,而不是因为这种特定的置换方法很有用).
请注意,因为类型Tin IShuffleFiveThings没有任何约束,除了通过类型转换(可能引入装箱)之外,实现将不能用它做很多事情.为这些参数添加约束使它们更有用.虽然可以在接口内对这些约束进行硬编码,但这会限制接口对需要这些特定约束的应用程序的有用性.使约束本身通用避免了这种限制.