回到过去他们设计一种提升和处理事件的共同风格时,为什么他们决定让EventArgs
成为一个班级?它完全是空的,没有任何通用代码,为什么它不是一个接口呢?
空类与空接口相比有什么优势?
通过使它成为一个类,它们采用了类的所有限制(即没有多重继承),而没有利用它的任何好处(即提供一些常见的行为)。
他们为什么不把这样的约会变成这样?有一个带有空接口参数的委托,该接口的实现表示没有额外信息的事件。
public interface IEventArgs { }
public class EventArgs : IEventArgs
{
public static EventArgs Empty { get { return _empty; } }
private static EventArgs _empty = new EventArgs();
}
public delegate void EventHandler(object sender, IEventArgs e);
public delegate void EventHandler<T>(object sender, T e) where T : IEventArgs;
假设你有两个既定惯例的事件:
public event EventHandler<CancelEventArgs> ReceivingMessage;
public event EventHandler<StringEventArgs> DroppingMessage;
public class StringEventArgs : EventArgs
{
public StringEventArgs(string data)
{
Data = data;
}
public string Data { get; private set; }
}
现在假设您想要将DroppingMessage
和字符串数据的取消功能添加到ReceivingMessage
事件处理程序。除非你想让它成为一个重大改变,否则这是唯一的方法:
public event EventHandler<CancelStringEventArgs> ReceivingMessage;
public event EventHandler<StringCancelEventArgs> DroppingMessage;
public class CancelStringEventArgs : CancelEventArgs
{
public CancelStringEventArgs(string data)
{
Data = data;
}
public string Data { get; private set; }
}
public class StringCancelEventArgs : StringEventArgs
{
public StringCancelEventArgs(string data) : base(data) { }
public bool Cancel { get; set; }
}
public class StringEventArgs : EventArgs
{
public StringEventArgs(string data)
{
Data = data;
}
public string Data { get; private set; }
}
现在,您有两个具有相同行为和重复代码的类,您必须深入研究词库,以考虑新的和创造性的方法来区分这些相同的类。另外,你让你的用户诅咒你的遗产(或继承,原谅双关语)因为他们必须在同一类中意识到这些差异。
另一方面,接口只是意味着采用这个原始代码......public event EventHandler<ICancelEventArgs> ReceivingMessage;
public event EventHandler<IStringEventArgs> DroppingMessage;
public interface IStringEventArgs : IEventArgs
{
string Data { get; }
}
public class StringEventArgs : IStringEventArgs
{
public StringEventArgs(string data)
{
Data = data;
}
public string Data { get; private set; }
}
...并添加一些轻微的不间断更改:
public event EventHandler<IStringCancelEventArgs> ReceivingMessage;
public event EventHandler<IStringCancelEventArgs> DroppingMessage;
public interface IStringEventArgs : IEventArgs
{
string Data { get; }
}
public interface IStringCancelEventArgs : IStringEventArgs, ICancelEventArgs { }
public class StringEventArgs : IStringCancelEventArgs
{
public StringEventArgs(string data)
{
Data = data;
}
public string Data { get; private set; }
public bool Cancel { get; set; }
}
作为旁注,将其指定为接口还允许在符合约定的事件的通用接口中进行协方差。然而,当时没有接口的这个功能,所以我明白为什么它没有被考虑在内。虽然它仍然让我感到悲伤。 :(
答案 0 :(得分:2)
使用.NET 4.5(http://msdn.microsoft.com/en-us/library/db0etb8x(v=vs.110))删除了TEventArgs
EventArgs
作为基类的限制。所以现在它与您希望的完全相同。
但我认为这样做是因为在这种情况下界面无用。 EventArgs
或IEventArgs
只是开发人员轻松发现事件数据类的标记。即使它是一个界面,你也不会使用它。由于您的订阅者希望从IEventArgs
继承的具体最终类型,而不是接口本身。所以这个接口只会添加不必要的附加类型声明,因为无论如何都需要EventArgs
来模拟空数据。
答案 1 :(得分:2)
我现在只能推测(我现在无法访问带注释的基类库的副本)。我的主要原因是定义一个继承链。是的,EventArgs
充当基础,并不提供任何功能。现在,检查CancelEventArgs
。它确实提供了一些功能(即,提供了Cancel
属性和一个额外的类构造函数)。但是,此类还充当许多子类的基类,例如DoWorkEventArgs
。
本质上,基类EventArgs
类只是作为所有事件参数的公共可靠基类。您可以编写只需要考虑中间类属性的代码(如Cancel
)。
答案 2 :(得分:2)
除了其他答案:EventArgs
并非完全没有任何功能 - 它提供了静态EventArgs.Empty
成员,这是一种统一的方式来提升没有数据的事件。