为什么我可以使用代表使用事件?

时间:2013-03-03 05:37:13

标签: c# .net events delegates

我知道事件总是与代表联系在一起。但是,我错过了一些事件的核心用法,并试图理解这一点。

我创建了一个简单的事件程序,如下所示,它工作得很好。

namespace CompleteRef3._0
{
delegate void someEventDelegate();

class EventTester
{
    public event someEventDelegate someEvent;

    public void doEvent()
    {
        if (someEvent != null) someEvent();
    }

}

class Program
{
    static void EventHandler1()
    {
        Console.WriteLine("Event handler 1 called..");
    }

    static void EventHandler2()
    {
        Console.WriteLine("Event handler 2 called..");
    }
    static void EventHandler3()
    {
        Console.WriteLine("Event handler 3 called..");
    }


    static void Main(string[] args)
    {
        EventTester evt = new EventTester();
        evt.someEvent += EventHandler1;
        evt.someEvent += EventHandler2;
        evt.someEvent += EventHandler3;
        evt.doEvent();
        Console.ReadKey();

    }
}
}

我用委托替换了事件声明。那就是我用上面的程序中的 someEventDelegate someEvent; 替换了行 公共事件someEventDelegate someEvent; ,而我仍然得到相同的结果。现在,我很困惑为什么我们需要使用事件,如果它只能由Delegates实现。事件的真正用途是什么?

没有事件的修改程序如下 -

namespace CompleteRef3._0
{
delegate void someEventDelegate();

class EventTester
{
    someEventDelegate someEvent;

    public void doEvent()
    {
        if (someEvent != null) someEvent();
    }

}

class Program
{
    static void EventHandler1()
    {
        Console.WriteLine("Event handler 1 called..");
    }

    static void EventHandler2()
    {
        Console.WriteLine("Event handler 2 called..");
    }
    static void EventHandler3()
    {
        Console.WriteLine("Event handler 3 called..");
    }


    static void Main(string[] args)
    {
        EventTester evt = new EventTester();
        evt.someEvent += EventHandler1;
        evt.someEvent += EventHandler2;
        evt.someEvent += EventHandler3;
        evt.doEvent();
        Console.ReadKey();

    }
}
}

4 个答案:

答案 0 :(得分:7)

事件的主要目的是防止订阅者互相干扰。如果您不使用活动,您可以:

通过重新分配代理(而不是使用+ =运算符)替换其他订阅者, 清除所有订户(通过将委托设置为null), 通过调用委托来向其他订阅者广播。

来源:坚果壳中的C#

答案 1 :(得分:6)

当然,您可以使用委托,因为在幕后,事件是包装委托的构造。

但是使用事件而不是委托的基本原理与使用属性而不是字段相同 - 数据封装。直接暴露字段(无论它们是什么 - 原始字段或委托)是不好的做法。

顺便说一下,您在委托字段之前错过了public关键字,以便在第二个代码段中实现。

使用第二个代码段的另一个“顺便说一句”:对于代理人,您应该使用Delegate.Combine而不是“+ =”。

答案 2 :(得分:6)

想象一下,你有3个订阅者对你的someEvent感兴趣。他们订阅了这样的东西:

客户1

EventTester evt = new EventTester();
evt.someEvent += Client1Handler1;
evt.someEvent += Cleint1Handler2;

客户2

EventTester evt = new EventTester();
evt.someEvent += Client2Handler1;
evt.someEvent += Client2Handler2;

客户3

EventTester evt = new EventTester();
evt.someEvent += Client2Handler1;
evt.someEvent += Client2Handler2;

现在想象另一个客户端这样做:

EventTester = null;

客户端1,2和3不会收到任何事件,因为您有这行代码:

if (someEvent != null) someEvent();

上面的代码行没有任何问题,但是使用委托有问题。

阿列克谢指出的另一个问题是:

someEvent = new someEventDelegate(EventHandler2)

如果你有一个event并且其中一个客户端尝试了上述操作,则不会允许它们出现编译错误,如下所示:

enter image description here

答案 3 :(得分:0)

public class Program
{
    public static void Main()
    {
        Number myNumber = new Number(100000);
        myNumber.PrintMoney();
        myNumber.PrintNumber();
        Console.ReadKey();
    }
}

public class Number
{
    private PrintHelper _printHelper;

    public Number(int val)
    {
        _value = val;

        _printHelper = new PrintHelper();
        //subscribe to beforePrintEvent event
        _printHelper.beforePrintEvent += printHelper_beforePrintEvent;
    }
    //beforePrintevent handler
    void printHelper_beforePrintEvent(string message)
    {
        Console.WriteLine("BeforePrintEvent fires from {0}", message);
    }

    private int _value;

    public int Value
    {
        get { return _value; }
        set { _value = value; }
    }

    public void PrintMoney()
    {
        _printHelper.PrintMoney(_value);
    }

    public void PrintNumber()
    {
        _printHelper.PrintNumber(_value);
    }

}
public class PrintHelper
{
    public delegate void BeforePrintDelegate(string message);
    public event BeforePrintDelegate beforePrintEvent;

    public PrintHelper()
    {

    }

    public void PrintNumber(int num)
    {
        if (beforePrintEvent != null)
            beforePrintEvent.Invoke("PrintNumber");

        Console.WriteLine("Number: {0,-12:N0}", num);

    }

    public void PrintDecimal(int dec)
    {
        if (beforePrintEvent != null)
            beforePrintEvent("PrintDecimal");

        Console.WriteLine("Decimal: {0:G}", dec);
    }

    public void PrintMoney(int money)
    {
        if (beforePrintEvent != null)
            beforePrintEvent("PrintMoney");

        Console.WriteLine("Money: {0:C}", money);
    }

    public void PrintTemperature(int num)
    {
        if (beforePrintEvent != null)
            beforePrintEvent("PrintTemerature");

        Console.WriteLine("Temperature: {0,4:N1} F", num);
    }
    public void PrintHexadecimal(int dec)
    {
        if (beforePrintEvent != null)
            beforePrintEvent("PrintHexadecimal");

        Console.WriteLine("Hexadecimal: {0:X}", dec);
    }
}