前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C# 值类型的局限性

C# 值类型的局限性

作者头像
用户9127601
发布2022-03-23 08:47:04
3710
发布2022-03-23 08:47:04
举报
文章被收录于专栏:dotNET编程大全

如果程序希望使用一个值类型实例来进行同步,通常都会是错误(bug)。但运行时应该认为这是非法并抛出异常吗?在下面的代码示例中如果两个不同的线程同时调用同一个Counter 实例的Increment 方法,将会发生什么?

代码语言:javascript
复制
    class Counter
    {
        private int _i;
        public int Increment()
        {
            lock (_i)
            {
                return ++_i;
            }
        }
    }

当我们打算这样做的时候,会发现这样一个意想不到的问题:C#编译器不允许lock关键字使值类型。不过,我们已经熟知lock关键字的内部原理,可以变通一下:

代码语言:javascript
复制
  class Counter
    {

        private int _i;
        public int Increment()
        {

            bool acquired = false;
            try
            {
                Monitor.Enter(_i, ref acquired);
                return ++_i;
            }
            finally
            {
                if (acquired) Monitor.Exit(_i);
            }
        }
    }

这样一来,程序就引入了一个错误(bug)。多个线程能够同时进入锁内修改_i,而且调 Monitor.Exit还会抛出异常.Monitor.Enter 方法接收的是System.Object类型的参数,是一个引用,而我们传递的是值类型(按值传递)。尽管此时(在需要引用的地方传递值),我们所传递的值并没有被更改,但是传递给 Monitor.Enter 方法的值与传递给Monitor.Exit方法的值具有不同的标识。类似地,在一个线程里传递给Monitor.Enter方法的值,与另一个线程里传递给Monitor.Enter的值也具有不同的标识。如果我们在需要引用的地方(按值)传递值,就不能获得正确的锁语义。

当方法返回引用类型时,如果我们返回了一个值类型,在语义上也不是非常合适。例如,下面的代码:

代码语言:javascript
复制
object GetInt()
{
int i = 42;
 return i; 
 }
object obj= GetInt();

GetInt方法按值返回一个值类型,然而调用者期望方法返回的是引用类型。方法本可以返回在方法执行时存储i的栈位置,但得到的将是到无效内存地址的引用,因为方法的栈帧会在方法返回前清空。这说明默认情况下按值复制的值类型语义,并不适合需要对象引用(指向托管堆)的地方。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-02-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 dotNET编程大全 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档