C#引发事件

8

最近我一直在使用C#,发现公司代码中大多数引发事件的代码都是这样写的:

EventHandler handler = Initialized;

if (handler != null)
{
    handler(this, new EventArgs());
}

我真的不明白为什么你不能这样做:
if (Initialized != null)
{
    Initialized(this, new EventArgs());
}

编辑:

有一些值得思考的问题,我尝试对此进行了一些测试:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Test t = new Test(true);

            while(true)
            {
                t.Ev += new EventHandler(t_Ev);
                t.Ev -= new EventHandler(t_Ev);
            }
        }

        static void t_Ev(object sender, EventArgs e)
        {
        }
    }

    public class Test
    {
        private readonly bool m_safe;

        public Test(bool safe)
        {
            m_safe = safe;

            Thread t = new Thread(Go);
           t.Start();
        }

        private void Go()
        {
            while (true)
            {
                if(m_safe)
                {
                    RaiseSafe();
                }
                else
                {
                    RaiseUnsafe();
                }
            }
        }

        public event EventHandler Ev;

        public void RaiseUnsafe()
        {
            if(Ev != null)
            {
                Ev(this, EventArgs.Empty);
            }
        }

        public void RaiseSafe()
        {
            EventHandler del = Ev;

            if (del != null)
            {
                del(this, EventArgs.Empty);
            }
        }
    }
}

不安全版本会导致程序崩溃。

4
我猜你需要问编写原始代码的人。 - David Heffernan
2
请看http://blogs.msdn.com/b/ericlippert/archive/2009/04/29/events-and-races.aspx。 - Eric Lippert
2个回答

9

第一个版本旨在尝试使事件线程安全。

请参见C# 事件和线程安全

事实上,正如讨论中所说,它并没有使事件线程安全。因此,我会使用第二个更简短的版本。

编辑:事件线程安全真的很难实现。看一下可能是什么样子... 如果您实际上没有处理多个线程注册/取消注册事件,就不应该浪费时间来进行线程安全。


2
嘿...我一直在尝试那个,但你比我先做了 :) - Richard B

0

第二个版本不是线程安全的。

if (Initialized != null)
{
    Initialized(this, new EventArgs());
}

如果最后一个处理程序在if (Initialized != null)之后取消订阅,则会出现空引用异常。

3
实际上,无论哪个版本都不是线程安全的,这取决于您对线程安全的定义。当然,您可以避免空指针引用,但第一个版本并没有避免在另一个线程上删除处理程序后可能调用已被删除的处理程序 - Eric Lippert

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接