我知道从另一个类调用一个事件几乎没有任何意义。
但是为了进行一些优化,我注意到如果没有设置事件,我可以提高性能。
可悲的是C#不允许我这样做
public class A
{
public event Action Event;
public bool IsEventSet { return Event != null; }
}
main
{
var a = new A();
var isSet = a.Event == null; //why is this not allowed! I can not understand
isSet = a.IsEventSet; //this seems like a hack to me!
}
我希望我足够清楚并且有理由这样做
这是有原因的吗?
谢谢!
答案 0 :(得分:4)
var isSet = a.Event == null; //why is this not allowed! I can not understand
为什么不允许?因为它是event
,而不是delegate
。
在c#中,event
只是一个有约束的委托。
在我意识到你可以像对待事件一样对待委托之前,我已经编写了多年的c#。具体来说,您可以将任意数量的订阅者附加和分离给一个代表。
以下代码演示了这一点:
using System;
public class A
{
public event Action Event;
// You could just use System.Action, but I want the example to be clear
public delegate void HandlerDelegateType();
public HandlerDelegateType PublicDelegate;
public void Fire()
{
if(PublicDelegate != null)
{
PublicDelegate();
}
}
}
public static class MainClass
{
public static int Main(string[] args)
{
var a = new A();
if(a.PublicDelegate == null)
{
Console.WriteLine("a.PublicDelegate is null");
}
a.PublicDelegate += () => { Console.WriteLine("First handler fired!"); };
a.PublicDelegate += () => { Console.WriteLine("Second handler fired!"); };
a.Fire();
if(a.PublicDelegate != null)
{
Console.WriteLine("a.PublicDelegate is not null");
}
return 0;
}
}
日志输出
a.PublicDelegate为null
第一个处理程序被解雇了!
第二个处理程序被解雇了!
a.PublicDelegate不为空
通过使用event
关键字,您明确限制了它的使用方式。
限制访问成员的方式是面向对象设计的关键方面。它允许您(设计师)了解您的课程将如何使用。虽然c#为您提供了此功能,但您可以高兴地不同意它并公开代理而不是事件。
<小时/> 现在我将承认短语&#34;只是一个有约束的代表&#34;过于简单化了。 实际上,您可以将事件公开为底层委托的公共接口,如下所示:
private HandlerDelegateType _privateDelegate;
public event HandlerDelegateType PublicEvent
{
add
{
_privateDelegate += value;
}
remove
{
_privateDelegate-= value;
if(_privateDelegate == null)
{
// Can perform some other action here
// For example, unsubscribe from a second event source
}
}
}
答案 1 :(得分:1)
C#不允许你这样做的原因是因为这里有很多语法糖可以帮助你。 C#中的事件与属性的关系非常密切,您通常使用的简短形式就像是自动属性。你实际上是让编译器为你做了很多工作。
也许有助于查看编译器为您生成的事件的完整声明。我下面的内容大致相当于编译器生成的内容。
public class A
{
public event Action Event
{
add
{
mEventBackingField = (Action) Delegate.Combine( mEventBackingField, value );
}
remove
{
mEventBackingField = (Action) Delegate.Remove( mEventBackingField, value );
}
}
private Action mEventBackingField;
}
我遗漏了编译器为了线程安全而抛出的其他垃圾,但这是写public event Action Event;
时发生的事情的一般要点。当您在类中引用Event
时,编译器基本上将其替换为对该事件的支持字段的引用。这允许您进行空检查并从类中引发事件。
从课外,唯一可见的是事件上的add
和remove
方法。没有办法真正看到底层代表。这是一件好事。
为什么呢?好吧,如果你被允许获得课外的基础代表值,你就可以从课外提出这个事件!任何地方的任何人都可以获得该事件的支持并调用已注册的代表。那将是一场维护噩梦。
但是如果你真的想让这种事情发生呢?那么,在这种情况下你不想要一个事件,你想要一个属性:
public class A
{
public Action Event { get; set; }
}