为什么不允许Lock(),却允许Monitor.Enter()?对于以下代码,我得到编译时错误,*'int'不是lock语句inti=0所要求的引用类型;锁定(我);但没有错误:inti=0;监控.Enter(i);据我所知,由于装箱引起的复杂性,值类型不应该用于锁定。但为什么它与Monitor一起工作。原因是lock是一种语言结构,编译器选择将额外的语义强加给表达式。Monitor.Enter只是一个方法调用,C#编译器不会以任何方式调用特殊情况,因此它会通过正常的重载解析和装箱。您绝对不应该在int上使用Monitor.Enter。它起作用的原因是因为int是装箱的,所以除非您存储对装箱值的引用,否则您将锁定一个临时对象,这意味着您不能无异常地调用Monitor.Exit。建议的锁定方法是创建一个私有只读对象并锁定它。对于静态方法,您可以使用私有静态对象。编译器的规范将锁的行为定义如下:锁语句表达式的编译时类型应为引用类型或>类型参数(§25.1.1),已知为引用类型。表达式的编译时类型表示值类型是编译时错误。然后,只要它编译,它就定义了它的等价物。因为Monitor.Exit只是一个没有任何约束的方法调用,它不会阻止编译器自动装箱int并继续其快乐(和非常)错误的方式。lock不仅仅是语法糖,就像foreach不仅仅是语法糖一样。生成的IL转换不会呈现给代码的其余部分,就好像那是编写的代码一样。在foreach中修改迭代变量是非法的(尽管结果输出代码中的IL级别没有任何内容可以防止这种情况发生)。在锁定中,编译器会阻止在编译时知道值类型,尽管导致IL并不关心这一点。顺便说一句:理论上,编译器可以“熟悉”这种(和其他)方法的深入知识,以便发现这种情况的明显情况,但从根本上说,在编译时总是不可能发现这种情况(考虑一个对象从另一种方法、程序集或通过反射传递进来的)太费心去发现任何这样的情况,以至于它可能会适得其反。编译器对API的内部结构了解得越多,如果您将来要更改API,就会遇到更多的问题。例如,可以添加Monitor.Enter()的重载,它接受一个int并锁定与int值关联的进程范围的互斥锁。这将符合监视器的规范(即使它可能很糟糕),但会给仍然可以快速阻止已经合法的操作的旧编译器带来大量问题。出于好奇,您对需要锁定的变量“i”做了什么?如果所有操作都是增量或其他操作,使用Interlocked类可能更有效:Interlocked.Increment(i);//线程安全的i++Interlocked类是.NET提供的最轻量级的线程同步工具,对于简单的递增、递减、读取或交换,它是最佳选择。如果你正在尝试同步一个行为块,那么我只创建一个可以用作同步根的对象:objectsyncRoot=newobject();//...lock(syncRoot){//在这里放置同步行为}我认为这是因为Monitor.Enter()是一个方法调用,所以编译器会自动进行装箱,而lock()是一个语法元素,所以编译器可以检查值类型并抛出错误。以上是C#学习教程:为什么不允许lock(),而允许Monitor.Enter()?如果所有分享的内容对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处:
