检测是否从另一个类设置了一个事件

时间:2016-04-28 23:16:44

标签: c#

我知道从另一个类调用一个事件几乎没有任何意义。

但是为了进行一些优化,我注意到如果没有设置事件,我可以提高性能。

可悲的是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!
}

我希望我足够清楚并且有理由这样做

这是有原因的吗?

谢谢!

2 个答案:

答案 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时,编译器基本上将其替换为对该事件的支持字段的引用。这允许您进行空检查并从类中引发事件。

从课外,唯一可见的是事件上的addremove方法。没有办法真正看到底层代表。这是一件好事。

为什么呢?好吧,如果你被允许获得课外的基础代表值,你就可以从课外提出这个事件!任何地方的任何人都可以获得该事件的支持并调用已注册的代表。那将是一场维护噩梦。

但是如果你真的想让这种事情发生呢?那么,在这种情况下你不想要一个事件,你想要一个属性:

public class A
{
    public Action Event { get; set; }
}