我完全意识到我提出的建议并不遵循.NET准则,因此,仅凭这个原因可能是一个糟糕的想法.但是,我想从两个可能的角度考虑这个问题:
(1)我是否应考虑将此用于我自己的开发工作,100%用于内部目的.
(2)这是框架设计者可以考虑改变或更新的概念吗?
我正在考虑使用一个使用强类型"发送者"的事件签名,而不是将其键入"对象",这是当前的.NET设计模式.也就是说,而不是使用如下所示的标准事件签名:
class Publisher
{
public event EventHandler<PublisherEventArgs> SomeEvent;
}
Run Code Online (Sandbox Code Playgroud)
我正在考虑使用一个使用强类型'sender'参数的事件签名,如下所示:
首先,定义一个"StrongTypedEventHandler":
[SerializableAttribute]
public delegate void StrongTypedEventHandler<TSender, TEventArgs>(
TSender sender,
TEventArgs e
)
where TEventArgs : EventArgs;
Run Code Online (Sandbox Code Playgroud)
这与Action <TSender,TEventArgs>并没有什么不同,但通过使用StrongTypedEventHandler,我们强制执行TEventArgs派生System.EventArgs.
接下来,作为示例,我们可以在发布类中使用StrongTypedEventHandler,如下所示:
class Publisher
{
public event StrongTypedEventHandler<Publisher, PublisherEventArgs> SomeEvent;
protected void OnSomeEvent()
{
if (SomeEvent != null)
{
SomeEvent(this, new PublisherEventArgs(...));
}
}
}
Run Code Online (Sandbox Code Playgroud)
上述安排将使订阅者能够使用不需要强制转换的强类型事件处理程序:
class Subscriber
{
void SomeEventHandler(Publisher sender, PublisherEventArgs e)
{
if (sender.Name == "John Smith")
{
// ...
}
}
} …Run Code Online (Sandbox Code Playgroud) 我搜索了档案,我发现了许多关于发件人是什么以及为什么要使用该模式的问题,但我没有看到任何关于自定义事件和类型的发件人.
假设我正在创建一个名为Subscription的自定义类,它实现了ISubscription,我有一些名为SubscriptionEventArgs的事件args.如果Subscription有一个名为Changed的事件,那么事件签名改变了什么错误(ISubscription sender,SubscriptionEventArgs e)?
一个小代码来帮助解决问题:
public class SubscriptionEventArgs : EventArgs
{
// guts of event args go here
}
public interface ISubscription
{
event Action<ISubscription, SubscriptionEventArgs> Changed;
}
public class Subscription : ISubscription
{
public event Action<ISubscription, SubscriptionEventArgs> Changed;
private void OnChanged(SubscriptionEventArgs e)
{
if (Changed!= null)
{
Changed(this, e);
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果您只是鄙视使用动作来代替"EventHandler",那么您可以使用自定义通用"EventHandler"执行相同的操作.
public delegate void EventHandler<TSender, TEventArgs>(TSender sender, TEventArgs e);
public class SubscriptionEventArgs : EventArgs
{
// guts of event args go here
}
public interface …Run Code Online (Sandbox Code Playgroud) 令我恼火的一件事是,在默认事件中,Sender属于object类型,因此在我们使用它之前几乎总是需要手动转换.幸运的是,由于VB现在也支持委托中的差异,我们可以以强类型发送者的方式更新事件的签名,请参阅:事件参数; "发件人为对象",或"发件人为T"?
遗憾的是,这对于发送者属于object类型的现有声明事件不起作用.
现在一个解决方案就是生成一个假的EventHandler,它在内部为你处理演员表.我做了一个简单的例子,见:
struct EventHandler<TSender, TEventArgs>
where TEventArgs: EventArgs
{
private readonly Action<TSender, TEventArgs> _delegate;
public EventHandler(Action<TSender, TEventArgs> @delegate)
{
if (@delegate == null)
throw new ArgumentNullException("@delegate");
_delegate = @delegate;
}
public static implicit operator EventHandler<TEventArgs>(EventHandler<TSender, TEventArgs> eventHandler)
{
return new EventHandler<TEventArgs>(eventHandler.Execute);
}
private void Execute(object sender, EventArgs e)
{
TSender typedSender = (TSender)sender;
TEventArgs typedEventArgs = (TEventArgs)e;
_delegate(typedSender, typedEventArgs);
}
}
Run Code Online (Sandbox Code Playgroud)
可以按照您的预期使用它:
class Program
{
event EventHandler<EventArgs> Test;
static void Main(string[] args)
{
new Program().Main();
}
void …Run Code Online (Sandbox Code Playgroud)