Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么我们需要“一个”呢;事件“;定义事件时使用关键字?_C#_.net - Fatal编程技术网

C# 为什么我们需要“一个”呢;事件“;定义事件时使用关键字?

C# 为什么我们需要“一个”呢;事件“;定义事件时使用关键字?,c#,.net,C#,.net,我不明白为什么我们在定义事件时需要“event”关键字,而我们可以不用“event”关键字做同样的事情,只需使用委托 e、 g 在这里,如果我从第二行中删除“event”关键字,那么我也可以通过调用委托来引发事件。有人能告诉我为什么需要这个事件关键字吗?这部分是需要的,因为如果省略事件关键字,就会破坏封装。如果它只是一个公共多播委托,任何人都可以调用它,将其设置为null或篡改它。如果存在一个名为MailNotifier的类,并且它有一个名为MailReceived的事件,则其他类型无法通过调用

我不明白为什么我们在定义事件时需要“event”关键字,而我们可以不用“event”关键字做同样的事情,只需使用委托

e、 g


在这里,如果我从第二行中删除“event”关键字,那么我也可以通过调用委托来引发事件。有人能告诉我为什么需要这个事件关键字吗?

这部分是需要的,因为如果省略
事件
关键字,就会破坏封装。如果它只是一个公共多播委托,任何人都可以调用它,将其设置为null或篡改它。如果存在一个名为
MailNotifier
的类,并且它有一个名为
MailReceived
的事件,则其他类型无法通过调用
MailNotifier.MailReceived()
触发该事件

另一方面,您只能从定义它的类型中处理和调用“类似于字段”的事件

如果您想保持事件调用的私密性,那么没有什么可以阻止您这样做:

public class MyClassWithNonFieldLikeEvent
{
   private CustomEventHandler m_delegate;

   public void Subscribe(CustomEventHandler handler) 
   {
      m_delegate += handler;        
   }

   public void Unsubscribe(CustomEventHandler handler)
   {          
      m_delegate -= handler;
   }

   private void DoSomethingThatRaisesEvent()
   {
      m_delegate.Invoke(...);
   }       
}

。。。但这只是为了(或多或少)完成类似于字段的事件已经提供给我们的全部代码。

与委托字段相比,事件具有明显的优势。与字段相比,事件可以在接口中定义,从而为代码添加了抽象,更重要的是:只能从定义类内部调用事件。在您的情况下,任何人都可以调用该事件,可能会破坏您的代码


有关更多信息,请参阅。

事件关键字执行3种不同的操作:

  • 即使不能在接口中定义常规字段,也可以在接口中定义事件
  • 它将
    =
    ()
    操作符(赋值和调用)的可见性更改为private,以便只有包含类可以调用事件或覆盖其中包含的所有方法。
    -=
    +=
    操作符仍然可以在定义事件的类之外的事件上调用(它们获取您在事件旁边编写的访问修饰符)
  • 您还可以覆盖
    -=
    +=
    在事件上的行为方式

  • 类似于字段的事件和委托类型的公共字段看起来相似,但实际上非常不同

    事件基本上类似于属性——它是一对添加/删除方法(而不是属性的get/set)。当您声明一个类似于字段的事件(即您自己没有指定添加/删除位的事件)时,将创建一个公共事件和一个私有备份字段。这允许您私下引发事件,但允许公开订阅。使用公共委托字段,任何人都可以删除其他人的事件处理程序,自己引发事件,等等-这是一个封装灾难


    有关活动(和代表)的更多信息,请阅读我的。(在某个时候,我需要为C#4更新它,它会像事件一样轻微地改变字段。尽管它的要点仍然是正确的。)

    其他答案都很好;我只想补充一点思考

    您的问题是“当我们有委托类型的字段时,为什么我们需要事件?”我想扩展这个问题:如果您有委托类型的字段,为什么您需要方法、属性、事件、实例构造函数或终结器?除了在类型中包含值和委托的字段之外,为什么还需要其他内容?为什么不直接说呢

    class C
    {
        private int z;
        public readonly Func<int, int> M = (int x)=>{ return x+z; }
        // ... and so on
    }
    
    C类
    {
    私人INTZ;
    公共只读函数M=(int x)=>{return x+z;}
    //……等等
    }
    
    ?

    您不需要方法、属性或事件。我们提供这些东西是因为方法、属性和事件设计模式非常重要和有用,应该有一个标准的、有文档记录的、清晰的方法来用这种语言实现它们

    是一种引用类型。它继承了。是一个修饰语。是委托的特殊修饰符。它修改了一些函数/方法的可访问性,例如Invoke方法。在被修饰符事件修改后,委托实例成为一个新概念“事件”。所以事件只是一个修改过的委托。您不能在定义事件的类之外直接更改引用或调用事件,但可以更改引用或调用普通委托实例。事件提供额外的保护,使事件具有更多的安全功能。 当您在定义事件的类之外时,允许您对事件执行两种类型的操作,“+=”和“-=”。 但是您可以访问普通委托实例的所有公共字段、属性、方法等。 以下是一个例子:

    namespace DelegateEvent
    {
    //下面这行的行为就像一个类。它确实是一个引用类型
    公共委托void MyDelegate(字符串输入);
    //以下行是非法的。它只能是一个实例。因此它不能直接位于命名空间下
    //公共事件MyEvent;
    公共类MyClassA
    {
    公共活动代表MyEventA;
    公共MyDelegate MyDelegateA;
    System.Threading.ManualResetEvent MyResetEvent=新的System.Threading.ManualResetEvent(错误);
    公共无效TryToDoSomethingOnMyDelegateA()
    {
    如果(MyDelegateA!=null)
    {
    //用户可以assecc所有公共方法。
    MyDelegateA(“我可以在classA中调用detegate”);//调用委托
    调用(“我可以在类A中调用detegate”);//调用委托
    IAsyncResult result=MyDelegateA.BeginInvoke(“我可以在类A中调用detegate”,MyAsyncCallback,MyResetEvent);//异步调用
    //用户可以检查委托实例的公共属性和字段
    System.Reflection.MethodInfo delegateAMethodInfo=MyDelegateA.Method;
    MyDelegateA=testMethod;//重置引用
    MyDelegateA=新的MyDelegate(testMethod);//重置引用
    MyDelegateA=null;
    
    class C
    {
        private int z;
        public readonly Func<int, int> M = (int x)=>{ return x+z; }
        // ... and so on
    }