hai*_*yyu 6 c# events delegates variance
我一直在尝试创建一个通用事件.基本上它应该是这样的:
namespace DelegateTest
{
class Program
{
static void Main(string[] args)
{
var lol = new SomeClass();
lol.SomeEvent += handler;
}
static void handler(object sender, SomeDerivedClass e)
{
}
}
class SomeClass
{
public delegate void SomeEventDelegate<in T>(object sender, T data);
public event SomeEventDelegate<ISomeInterface> SomeEvent;
}
interface ISomeInterface
{
}
class SomeDerivedClass : ISomeInterface
{
}
}
Run Code Online (Sandbox Code Playgroud)
我想允许用户传递任何委托,其中第二个参数派生自"ISomeInterface".
"in"指定反差,对吗?这意味着如果API期望更通用的东西,你可以传递更具体的东西(在我的基础"ISomeInterface"将是通用的,而我的"SomeDerivedClass"将是特定的.)但是,我被告知我的编译器"方法处理程序没有重载匹配DelegateTest.SomeClass.SomeEventDelegate."
我想知道为什么这不起作用.如果是这样会导致什么问题?或者我错过了一些工作的东西?
提前致谢!
"in"指定反差,对吗?
是.
这意味着如果API期望更通用的东西,你可以传递更具体的东西(在我的基础"ISomeInterface"将是通用的,而我的"SomeDerivedClass"将是特定的).
否.委托反演允许委托引用一种方法,该方法的参数类型少于委托类型.例如,假设ISomeInterface有一个基本接口:
interface ISomeBaseInterface
{
}
interface ISomeInterface : ISomeBaseInterface
{
}
Run Code Online (Sandbox Code Playgroud)
并假设handler了ISomeBaseInterface,而不是SomeDerivedClass:
static void handler(object sender, ISomeBaseInterface e)
Run Code Online (Sandbox Code Playgroud)
然后new SomeClass().SomeEvent += handler会工作.
这就是为什么原始代码不是类型安全的原因:当SomeClass引发时SomeEvent,它可能会传递任何实现ISomeInterface为data参数的代码.例如,它可以传递一个实例SomeDerivedClass,但它也可以传递一个实例
class SomeOtherDerivedClass : ISomeInterface
{
}
Run Code Online (Sandbox Code Playgroud)
如果您能够注册void handler(object sender, SomeDerivedClass e)该事件,该处理程序将最终被调用SomeOtherDerivedClass,这不起作用.
总之,您可以注册比事件类型更通用的事件处理程序,而不是更具体的事件处理程序.
更新:你评论说:
好吧,我实际上想要遍历列表并检查类型.因此,如果要使用类型为letOtherDerivedObject的数据对象触发事件,则程序将遍历订阅该事件的方法列表,直到找到与该签名匹配的方法(对象,SomeOtherDerivedObject).所以事件本身只会用于存储,而不是实际调用代理.
我不认为C#允许你声明一个event适用于任意委托类型的东西.以下是编写添加事件处理程序并调用它们的方法的方法:
class SomeClass
{
private Delegate handlers;
public delegate void SomeEventDelegate<in T>(object sender, T data);
public void AddSomeEventHandler<T>(SomeEventDelegate<T> handler)
{
this.handlers = Delegate.Combine(this.handlers, handler);
}
protected void OnSomeEvent<T>(T data)
{
if (this.handlers != null)
{
foreach (SomeEventDelegate<T> handler in
this.handlers.GetInvocationList().OfType<SomeEventDelegate<T>>())
{
handler(this, data);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)