引自:http: //msdn.microsoft.com/en-us/library/aa645739(VS.71).aspx
"调用事件只能在声明事件的类中完成."
我很困惑为什么会有这样的限制.如果没有这个限制,我将能够编写一个类(一个类),这个类一次用于管理发送给定类别的事件 - 比如INotifyPropertyChanged.
有了这个限制,我必须重新复制并粘贴相同(相同!)的代码.我知道C#的设计者不重视代码重用太多(*),但是gee ...复制和粘贴.这有多高效?
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
Run Code Online (Sandbox Code Playgroud)
在每个班级改变一些事物,到你生命的尽头.害怕!
所以,虽然我正在恢复我的额外发送课程(我太容易上当了),以旧的,"好"的复制和粘贴方式,你能看到吗?
如果你知道如何避免这种限制的任何技巧 - 也不要犹豫回答!
(*)具有多重继承我可以更好地编写通用发送方,但是C#没有多重继承
介绍界面
public interface INotifierPropertyChanged : INotifyPropertyChanged
{
void OnPropertyChanged(string property_name);
}
Run Code Online (Sandbox Code Playgroud)
为PropertyChangedEventHandler添加新的扩展方法Raise.然后为此新接口添加mediator类,而不是基本的INotifyPropertyChanged.
到目前为止,它是最小的代码,让我们代表它的所有者从嵌套对象发送消息(当所有者需要这样的逻辑时).
谢谢大家的帮助和想法.
Guffa写道:
"通过从外部触发事件,你无法做出任何事情,"
这很有意思,因为......我可以.这正是我要问的原因.看一看.
假设你有类字符串.不好意思吧?但是让我们用Invoker类打包它,它每次发生变化时都会发送事件.
现在:
class MyClass : INotifyPropertyChanged
{
public SuperString text { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
现在,当文本被更改时,MyClass被更改.因此,当我在文本内部时,我知道,如果我只拥有所有者,那么它也会被更改.所以我可以代表它发送活动.它在语义上是100%正确的.
备注:我的课程稍微聪明一点 - 所有者设置是否有这样的逻辑.
传递事件处理程序的想法 - "2"将不会显示.
public class Mediator
{
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string property_name)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(property_name));
}
public void Link(PropertyChangedEventHandler send_through)
{
PropertyChanged += new PropertyChangedEventHandler((obj, args) => {
if (send_through != null)
send_through(obj, args);
});
}
public void Trigger()
{
OnPropertyChanged("hello world");
}
}
public class Sender
{
public event PropertyChangedEventHandler PropertyChanged;
public Sender(Mediator mediator)
{
PropertyChanged += Listener1;
mediator.Link(PropertyChanged);
PropertyChanged += Listener2;
}
public void Listener1(object obj, PropertyChangedEventArgs args)
{
Console.WriteLine("1");
}
public void Listener2(object obj, PropertyChangedEventArgs args)
{
Console.WriteLine("2");
}
}
static void Main(string[] args)
{
var mediator = new Mediator();
var sender = new Sender(mediator);
mediator.Trigger();
Console.WriteLine("EOT");
Console.ReadLine();
}
Run Code Online (Sandbox Code Playgroud)
作为对所有关于滥用直接事件调用的争论的评论 - 滥用当然是可能的.所需要的只是实现上述解决方法.
我的代码的小样本(最终用途),Dan请看看:
public class ExperimentManager : INotifierPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string property_name)
{
PropertyChanged.Raise(this, property_name);
}
public enum Properties
{
NetworkFileName,
...
}
public NotifierChangedManager<string> NetworkFileNameNotifier;
...
public string NetworkFileName
{
get { return NetworkFileNameNotifier.Value; }
set { NetworkFileNameNotifier.Value = value; }
}
public ExperimentManager()
{
NetworkFileNameNotifier =
NotifierChangedManager<string>.CreateAs(this, Properties.NetworkFileName.ToString());
...
}
Run Code Online (Sandbox Code Playgroud)
在开始咆哮之前想一想.如果任何方法可以在任何对象上调用事件,那么这不会破坏封装并且也会令人困惑吗?事件的关键是,具有事件的类的实例可以通知其他对象发生了某些事件.该活动必须来自该课程而不是任何其他课程.否则,事件变得毫无意义,因为任何人都可以随时触发任何对象上的任何事件,这意味着当事件触发时,您不确定它是否真的是因为它所代表的行为发生了,或者仅仅因为某些第三方类决定了有一些乐趣.
也就是说,如果您希望能够允许某种类型的中介类发送事件,只需使用添加和删除处理程序打开事件声明.然后你可以做这样的事情:
public event PropertyChangedEventHandler PropertyChanged {
add {
propertyChangedHelper.PropertyChanged += value;
}
remove {
propertyChangedHelper.PropertyChanged -= value;
}
}
Run Code Online (Sandbox Code Playgroud)
然后propertyChangedHelper变量可以是某种类型的对象,它实际上会为外部类触发事件.是的,您仍然需要编写添加和删除处理程序,但它相当小,然后您可以使用您想要的任何复杂性的共享实现.