Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/csharp-4.0/2.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# 4.0 C-为事件设置空委托_C# 4.0_Event Handling - Fatal编程技术网

C# 4.0 C-为事件设置空委托

C# 4.0 C-为事件设置空委托,c#-4.0,event-handling,C# 4.0,Event Handling,上述结构允许不检查是否存在任何订户: public event EventHandler MyButtonClick = delegate { }; 代替 public virtual void OnMyButtonClick(EventHandler e) { this.MyButtonClick(this, e); } 但这真的是个好主意吗?这是唯一的好处:不检查是否有订户存在 更新:下面是一个例子 public virtual

上述结构允许不检查是否存在任何订户:

public event EventHandler MyButtonClick = delegate { };
代替

public virtual void OnMyButtonClick(EventHandler e)
        {
            this.MyButtonClick(this, e);
        }
但这真的是个好主意吗?这是唯一的好处:不检查是否有订户存在

更新:下面是一个例子

  public virtual void OnMyButtonClick(EventHandler e)
            { 
                if (MyButtonClick!=null)
                   this.MyButtonClick(this, e);
            }

你不需要那样做。如果使用您类的客户端不会为MyButtonClick事件添加处理程序订阅服务器,则代码不会引发异常

这就是事件和委托的工作方式,因为它们是相同的东西,否则您将被迫向类的所有事件添加一个处理程序(假设存在任何事件)

因此,您可以执行以下操作:

namespace ConsoleApplication2
{
    public class TestClass
    {
        public event EventHandler MyButtonClick;
            //= delegate { };

        public void OnButtonClick(EventArgs e)
        {
            MyButtonClick(this, e);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var testClass = new TestClass();
            //it throws an exception
            testClass.OnButtonClick(new EventArgs());

            // if you add an handler it will call it

            testClass.MyButtonClick += myCustomHandler;
            testClass.OnButtonClick(new EventArgs()); // myCustomHandler has been invoiked

        }

        private static void myCustomHandler(object sender, EventArgs e)
        {
            Console.WriteLine("myCustomHandler has been invoiked");
        }
    }
}
请看下面的示例:

public virtual void OnMyButtonClick(EventArgs e)
{ 
   MyButtonClick(this, e);
}

你不需要那样做。如果使用您类的客户端不会为MyButtonClick事件添加处理程序订阅服务器,则代码不会引发异常

这就是事件和委托的工作方式,因为它们是相同的东西,否则您将被迫向类的所有事件添加一个处理程序(假设存在任何事件)

因此,您可以执行以下操作:

namespace ConsoleApplication2
{
    public class TestClass
    {
        public event EventHandler MyButtonClick;
            //= delegate { };

        public void OnButtonClick(EventArgs e)
        {
            MyButtonClick(this, e);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var testClass = new TestClass();
            //it throws an exception
            testClass.OnButtonClick(new EventArgs());

            // if you add an handler it will call it

            testClass.MyButtonClick += myCustomHandler;
            testClass.OnButtonClick(new EventArgs()); // myCustomHandler has been invoiked

        }

        private static void myCustomHandler(object sender, EventArgs e)
        {
            Console.WriteLine("myCustomHandler has been invoiked");
        }
    }
}
请看下面的示例:

public virtual void OnMyButtonClick(EventArgs e)
{ 
   MyButtonClick(this, e);
}

那么,您在这里给出的代码:

public class TestClass
{
    public event EventHandler MyButtonClick = delegate { };

    public void ButtonClick(EventArgs e)
    {
        MyButtonClick(this,e);
    }
}

class Program
{
    static void Main(string[] args)
    {
        var testClass=new TestClass();
        testClass.ButtonClick(new EventArgs());

        // if you add an handler it will call it

        testClass.MyButtonClick += myCustomHandler;
        testClass.ButtonClick(new EventArgs()); // myCustomHandler has been invoiked

    }

    private static void myCustomHandler(object sender, EventArgs e)
    {
        Console.WriteLine("myCustomHandler has been invoiked");
    }
}
这不是线程安全的。如果在空性检查之后但在调用之前删除了最终订阅,则最终可能会出现NullReferenceException,这取决于引发线程是否看到更改

因此,您可以将其改为:

public virtual void OnMyButtonClick(EventHandler e)
{ 
    if (MyButtonClick!=null)
       this.MyButtonClick(this, e);
}
。。。当然,你可能会忘记这样做,即使你不这样做,在我看来,在各地这样做是很麻烦的。所以,是的,虽然好处只是避免了无效性检查,但我认为在很多情况下,这并不是一个坏的权衡。在我看来,任何让人更难犯错误的事情都是个好主意

另一种选择是使用扩展方法:

public virtual void OnMyButtonClick(EventArgs e)
{ 
    var handler = MyButtonClick;
    if (handler != null)
    {
        handler(this, e);
    }
}
然后将您的呼叫代码更改为:

public static void SafeInvoke(this EventHandler handler, object sender,
                              EventArgs e)
{
    if (handler != null)
    {
        handler(sender, e);
    }       
}

并对其他事件使用相同的代码。您可能还需要EventHandler的通用表单。

好的,您在这里给出的代码:

public class TestClass
{
    public event EventHandler MyButtonClick = delegate { };

    public void ButtonClick(EventArgs e)
    {
        MyButtonClick(this,e);
    }
}

class Program
{
    static void Main(string[] args)
    {
        var testClass=new TestClass();
        testClass.ButtonClick(new EventArgs());

        // if you add an handler it will call it

        testClass.MyButtonClick += myCustomHandler;
        testClass.ButtonClick(new EventArgs()); // myCustomHandler has been invoiked

    }

    private static void myCustomHandler(object sender, EventArgs e)
    {
        Console.WriteLine("myCustomHandler has been invoiked");
    }
}
这不是线程安全的。如果在空性检查之后但在调用之前删除了最终订阅,则最终可能会出现NullReferenceException,这取决于引发线程是否看到更改

因此,您可以将其改为:

public virtual void OnMyButtonClick(EventHandler e)
{ 
    if (MyButtonClick!=null)
       this.MyButtonClick(this, e);
}
。。。当然,你可能会忘记这样做,即使你不这样做,在我看来,在各地这样做是很麻烦的。所以,是的,虽然好处只是避免了无效性检查,但我认为在很多情况下,这并不是一个坏的权衡。在我看来,任何让人更难犯错误的事情都是个好主意

另一种选择是使用扩展方法:

public virtual void OnMyButtonClick(EventArgs e)
{ 
    var handler = MyButtonClick;
    if (handler != null)
    {
        handler(this, e);
    }
}
然后将您的呼叫代码更改为:

public static void SafeInvoke(this EventHandler handler, object sender,
                              EventArgs e)
{
    if (handler != null)
    {
        handler(sender, e);
    }       
}

并对其他事件使用相同的代码。您可能还需要EventHandler的通用表单。

它是否允许您这样做?如果有人设置MyButtonClick=null;?这不应该起作用,您不能重新指定事件名称。@LKIM,您是什么意思?新建TestClass.MyButtonClick=null;?它未编译。请尝试以下操作:类测试{public event EventHandler MyEvent=delegate{};public void firevent{MyEventthis,EventArgs.Empty;}public void ClearEvent{MyEvent=null;}}}静态类程序{[STAThread]static void Main{Test t=new Test;t.firevent;t.MyEvent+=new EventHandlert\u MyEvent;t.firevent;t.ClearEvent;t.firevent;}静态无效t\u MyEventobject发送方,EventArgs e{Console.writelineet\u MyEvent;}执行不起任何作用的代码有点傻。但这并不重要,你永远不会注意到单击事件的区别。它甚至允许你这样做吗?如果有人设置MyButtonClick=null;?那不应该起作用,你不能重新分配事件名。@LKIM,你是什么意思?new TestClass.MyButtonClick=null;?它不起作用请尝试以下操作:类测试{public event EventHandler MyEvent=delegate{};public void firevent{MyEventthis,EventArgs.Empty;}public void ClearEvent{MyEvent=null;}}静态类程序{[STAThread]静态void Main{Test t=new Test;t.firevent;t.MyEvent+=new EventHandlert\u MyEvent;t.firevent;t.ClearEvent;t.firevent;}静态无效t\u MyEventobject发送方,EventArgs e{Console.writelineet\u MyEvent;}执行什么都不做的代码有点傻。但这并不重要,你永远不会注意到单击事件的区别。我确信如果没有事件处理程序,它不会抛出错误。你可以做一个测试来更好地理解,但它不会让C的作者不同意你的观点。你的更新是错误的。testClass.OnButtonCli请确认它必须是一个委托,您应该将其视为一个字段。根据MSDN:一旦一个类声明了一个事件,它就可以将该事件视为指定委托类型的字段。我确信,如果没有事件处理程序,它不会抛出错误。您可以做一个测试来更好地理解它,但C的作者不会同意您的观点。您的更新错误。testClass.OnButton单击i
t必须是一个委托,您应该将其视为一个字段。来自MSDN:一旦一个类声明了一个事件,它就可以将该事件视为指示委托类型的字段(C的作者)!哇!我问这个问题是因为你在书中的文章。这解决了我三年来遇到的一个奇怪的线程问题/我被这个答案弄糊涂了——是将一个事件分配给一个空委托,然后不进行复制/检查/调用,这是一种公认的做法,还是它不是线程安全的?@ScottSEA:它是安全的,但并没有被广泛使用。不是线程安全的是OP在问题中包含的检查/调用!哇!我问这个问题是因为你在书中的文章。这解决了我三年来遇到的一个奇怪的线程问题/我被这个答案弄糊涂了——是将一个事件分配给一个空委托,然后不进行复制/检查/调用,这是一种公认的做法,还是它不是线程安全的?@ScottSEA:它是安全的,但并没有被广泛使用。问题中包含的OP检查/调用不是线程安全的。