【发布时间】:2010-09-04 15:12:58
【问题描述】:
引用自: http://msdn.microsoft.com/en-us/library/aa645739(VS.71).aspx
“只能在声明事件的类中调用事件。”
我很困惑为什么会有这样的限制。如果没有这个限制,我将能够编写一个类(一个类),它曾经可以很好地管理发送给定类别的事件——比如 INotifyPropertyChanged。
由于这个限制,我必须重新复制和粘贴相同(相同!)的代码。我知道 C# 的设计者不太重视代码重用 (*),但是,哎呀……复制和粘贴。效率如何?
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
在每一堂课中都会改变一些东西,直到你生命的尽头。可怕!
所以,当我将额外的发送类(我太轻信)恢复为旧的“好”复制和粘贴方式时,你能看到
为发送者发送事件的能力会发生什么可怕的事情?
如果您知道如何避免此限制的任何技巧 - 也不要犹豫回答!
(*) 多继承我可以用更清晰的方式编写一次通用发送方,但是 C# 没有多继承
编辑
迄今为止最好的解决方法
介绍界面
public interface INotifierPropertyChanged : INotifyPropertyChanged
{
void OnPropertyChanged(string property_name);
}
为 PropertyChangedEventHandler 添加新的扩展方法 Raise。然后为这个新接口添加中介类,而不是基本的 INotifyPropertyChanged。
到目前为止,让我们代表其所有者从嵌套对象向您发送消息的代码最少(当所有者需要此类逻辑时)。
感谢大家的帮助和想法。
编辑 1
古法写道:
“你不能通过从外部触发事件来导致某事发生,”
这很有趣,因为...我可以。这正是我要问的原因。看看吧。
假设你有类字符串。不有趣,对吧?但是让我们将它与 Invoker 类一起打包,它会在每次更改时发送事件。
现在:
class MyClass : INotifyPropertyChanged
{
public SuperString text { get; set; }
}
现在,当文本改变时,MyClass 也改变了。因此,当我在文本中时,我知道,如果只有我拥有所有者,它也会被更改。所以我可以代表它发送事件。而且它在语义上是 100% 正确的。
备注:我的班级只是稍微聪明一点——所有者设置它是否希望有这样的逻辑。
编辑 2
传递事件处理程序的想法——“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();
}
编辑 3
作为对所有关于滥用直接事件调用的争论的评论——滥用当然仍然是可能的。只需实施上述解决方法即可。
编辑 4
我的代码小示例(最终使用),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());
...
}
【问题讨论】:
-
一直在想同样的问题很多次 :) 等待一个好的答案。
-
(*) 不是C#不支持多重继承,是.NET框架。
-
有一个东西是 too 太多抽象,将这 2 行(或在您的情况下为 4 行)代码的工作委托给外部帮助程序类似乎很棒例子。
-
另外,您可以在 PropertyChangedEventHandler 上创建一个名为“Raise”的扩展方法,以便您的实现是 PropertyChanged.Raise(this, name);对我来说似乎很简洁。
-
@macias:我认为你误解了 Kirk Woll 的建议。在
PropertyChangedEventHandler上编写一个扩展方法,完全可以做到他所描述的。然后,您将在声明事件的类中使用此扩展方法,而无需编写您的OnPropertyChanged代码。它不会为您节省所有的输入;但它确实可以为您节省一些。