经验笔记 - C#的自增自减运算符重载和i=i++中i值不变的原因,真的是“先取值再自增”?

最近逛CSDN发现个问题

int i = 0;

i = i++;

Consloe.Write(i);

发现输出为0的情况,有各种各样的解释

比如说,后缀++是先取值赋值给i,再进行i=i+1的操作。

我觉得这不是个合理的解释,先取值赋值给i,那i这时候等于0,在进行i=i+1的操作,i就应该等于1了。

无论等号左边右边怎样,变量i在内存中的位置都应该是同一个,所以就算是先取值再自增,那自增的都会是i。

所以我觉得,先取值再自增的解释并不合理,或者说后缀++是先取值再自增的这个说法就是错误的。

但去翻了各种贴子资料,都没有直接抨击这个说法,也去翻了C#文档也没有提及++的底层实现(可能有,只是我没找到)

那只好自己动手了。

如何证明呢,从运算符优先级运算符重载上我找到了思路。

1.运算符优先级:++的优先级要高于=的优先级,所以在进行=操作时,++运算符必须得运算完毕,不会存在任何延时操作,也就是++的运算符不能分两步走,不能一步取值在=号前,一步自增在=后。

所以我觉得取值和自增都得在一个“时间“完成。

这一个时间是多久呢,从++运算符重载就能知道,是在一个函数(方法)

2.++运算符重载:如果让你在一个方法内实现先取值再自增,你会怎么做呢?

开启一个新线程挂起,然后等取值操作执行完,这是很不合理的。

合理的方案是,用一个temp保存自增前的值,然后自增,最后返回temp。

再来看 i=i++ , 用temp保存原来的值temp=0,i自增i=1,返回temp,即i=temp=0。i有自增,但被temp覆盖,所以i值不变。

这很合理不是吗,怎么验证一下呢。(可以反编译之类的高端操作,无奈我不会)

在C++中自增操作符重载分前缀重载和后缀重载,你要在一个方法内前缀重载,完成先取值再自增,我认为这完全不用验证了,这就是正确的,也没办法验证。(找了好久都找不到底层int++的代码)

在C#中自增操作符的重载不分前后缀,是底层帮我们实现了前缀和后缀的区别

public struct Age //注意是结构体
{
    public int Value;

    public Age(int value)
    {
        Value = value;
    }

    //前后缀++都是同一种重载方式,调用时底层自动区分前后缀实现
    public static Age operator ++(Age age) 
    {
        age.Value += 1;

        return age;
    }
}

class Program
{
    static void Main(string[] args)
    {
        var myAge = new Age(18);

        Console.WriteLine("myAge.value = " + myAge.Value);

        myAge = myAge++;

        Console.WriteLine("myAge.value = " + myAge.Value);

        Console.ReadKey();
    }
}

输出

 

当把struct改成class时

public class Age //注意是类
{
    ……
}

输出,如果是引用类型,就不存在前后缀的区别

可以推测底层是这样的

后缀++(Age age)
{
    var temp = age;
    age++(); //调用age++的方法
    return temp;
}

所以值类型的temp不受影响,而引用类型temp会随原来的age改变,也就是引用类型的自增不分前后缀,都是返回自增后的值

总结:后缀++,先取值再自增,是对方法内的说法。对方法外应该是,进行自增但返回自增前的值。

(不是很严谨,但我觉得足够了,三五年后我可能能找到更直接的证明方法。)

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值