Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/306.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#_Delegates_Thread Safety - Fatal编程技术网

在C#中,为什么要将委托分配给本地副本线程安全,任何代码都可以证明这一点?

在C#中,为什么要将委托分配给本地副本线程安全,任何代码都可以证明这一点?,c#,delegates,thread-safety,C#,Delegates,Thread Safety,我听说C#中的多播委托是不可变的,但下面的代码似乎证明了这一点 Action a = () => { }; Action b = a; Console.WriteLine(ReferenceEquals(a, b)); 它将显示True而不是False。下面是另一个例子: public delegate void MyHandler(); public class Klass { public event MyHandler onCreate; public void

我听说C#中的多播委托是不可变的,但下面的代码似乎证明了这一点

Action a = () => { };
Action b = a;
Console.WriteLine(ReferenceEquals(a, b));
它将显示True而不是False。下面是另一个例子:

public delegate void MyHandler();
public class Klass
{
    public event MyHandler onCreate;

    public void Create()
    {
        MyHandler handler = onCreate;
        if (handler != null)
        {
            handler();
        }

        Console.WriteLine(ReferenceEquals(handler, onCreate));
    }
}
该类将按如下方式调用:

Klass k = new Klass();
k.onCreate += () => { };

k.Create();
与上面相同,它将显示True,那么如果本地副本与原始副本是相同的引用,那么它怎么可能是线程安全的呢

如果本地副本与原始副本是相同的引用,那么它怎么可能是线程安全的呢

我想你可能误解了不变性的含义。维基百科是这样定义的:

在面向对象和函数式编程中,不可变对象是一个对象,其状态在创建后不能修改。这与可变对象不同,可变对象可以在创建后进行修改


从变量
A
b
的引用分配不会更改代理的状态。因此,调用同一委托的多个线程保证调用同一构造的委托。注意,这并不意味着该委托引用的底层方法是线程安全的。记住,C#中的委托是引用类型,它们是按值复制的,在它们的情况下,值是GC堆中保存的对象的地址,而不是值本身的副本。有关委派线程安全的更多信息,请参见

有两个概念使此模式成为线程安全的

  • 委托是不可变的。一旦它被创建,它将永远不会改变。这意味着您可以在代码中使用它,而不必担心其他线程会更改它
  • 引用分配是原子的。将引用复制到局部变量可防止清除多播链的一个线程与当前线程之间出现争用情况,前提是该线程将引用非
    null

这里一个可能的混淆是,事件的工作原理类似于变量,因为它包含对多播委托的引用。当您对它执行
+=
-=
操作时,它将构造一个新的多播委托,并将新创建的对象分配给事件“变量”。委托仍然是不可变的,因此它永远不会更改。该事件不是,并且可以由另一个线程更改。

但下面的代码似乎证明它不是。不,没有。你只是在做参考咨询,没别的。不变性并不是多次引用一个对象,而是在其状态发生变化时拥有一个新副本。您可能想看看关于旧问题的好答案!:)