【问题标题】:Are C# Proto3 classes immutable?C# Proto3 类是不可变的吗?
【发布时间】:2018-12-31 18:29:29
【问题描述】:

我将一个引用类型(生成的 Proto3)传递给一个更新某些属性的方法。当方法返回时,属性已恢复,就好像它不是通过引用传递或不可变一样。

MyData dest = new MyData();
dest.Num = 1;

MyData src = new MyData();
src.Num = 2;

Console.WriteLine(dest.Num); // num = 1
Test(src, dest);
Console.WriteLine(dest.Num); // num still equals 1

public static void Test(MyData src, MyData dest)
{
    // dest.Num = 1 here
    dest = src;
    // dest.Num = 2 now
}

【问题讨论】:

  • 您刚刚更改了dest 参数的值。这是一个按值传递的参数——你没有使用ref。如果改为使用dest.Num = 3;,则会更改dest 引用的对象的内容。请参阅pobox.com/~skeet/csharp/parameters.html - 请注意,这与 Protobuf 无关,这只是 C# 的一般工作方式。
  • 实际上我昨天刚刚阅读了您的文章,试图解决这个问题。只是为了验证,值类型和引用类型是按值传递的,除非您使用 ref 关键字。但是,您仍然可以在没有ref 的情况下修改引用类型引用的数据。您只是不能更改实际参考本身吗?
  • 是的,完全正确。如果你还没有读过pobox.com/~skeet/csharp/references.html,我也会读。

标签: c# immutability proto3


【解决方案1】:

srcdest 按值传递。当您分配dest=src 时,您只是将src 分配给一个曾经指向dest 的局部变量,这不会影响dest 本身。

当然,如果您愿意,您可以通过修改其成员来修改方法内部的dest,例如:

public static void Test(MyData src, MyData dest)
{
    dest.Num = src.Num;
}

【讨论】:

    【解决方案2】:

    您选择重用变量名可能会混淆问题。让我们解决这个问题:

    MyData foo = new MyData();
    foo.Num = 1;
    
    MyData bar = new MyData();
    bar.Num = 2;
    
    Console.WriteLine(foo.Num); // num = 1
    Test(bar, foo);
    Console.WriteLine(foo.Num); // num still equals 1
    
    public static void Test(MyData src, MyData dest)
    {
        // dest.Num = 1 here
        dest = src;
        // dest.Num = 2 now
    }
    

    现在让我们看看Test 做了什么。它将dest 的值重新分配src。它不会更改 destsrc 引用的对象的值。所以调用函数中的foobar 仍然引用相同的对象,所以你的结果是预期的。

    如果您在Test 中将dest 设为ref 变量,那么您会看到foo 发生变化,因为Test 会改变实际引用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-01-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-06
      • 2017-11-17
      • 2010-11-20
      • 2014-10-03
      相关资源
      最近更新 更多