【问题标题】:Passing a readonly struct as an "in" parameter?将只读结构作为“in”参数传递?
【发布时间】:2021-05-22 11:14:10
【问题描述】:

根据in参数修饰符的所有已知规律,任何传递的对象都将通过引用传递但不能被调用的方法修改。

所以我发现微软在How to write safe and efficient C# code 上的这个建议令人困惑:

声明一个只读结构来表示一个类型是不可变的。这使编译器能够在使用 in 参数时保存防御性副本。

永远不要将结构作为 in 参数传递,除非它使用 readonly 修饰符声明或方法仅调用结构的只读成员。违反本指南可能会对性能产生负面影响,并可能导致行为不明。

如果方法不允许修改它,为什么编译器在使用“in”参数时会保存防御性副本?

如果不允许该方法修改它,如何将非只读结构作为 in 参数传递会对性能产生负面影响并导致晦涩的行为?

【问题讨论】:

  • 相关stackoverflow.com/questions/52820372/…(编辑:甚至可能重复)
  • @TimSchmelter,相关,是的,但我不会说重复,因为该问题询问“in”修饰符的意义,而我要求澄清微软的看似(到我)关于使用结构和 in 修饰符的有争议的建议。
  • 你是对的,所以不是重复的,但你可以在那里和linked blog中找到答案(尤其是“in-modifier的性能特征”)。
  • @TimSchmelter,好的,我会看看那个。但这需要一些时间。如果我在该博客中找到答案,我应该返回并编辑/关闭我的问题吗?

标签: c# struct parameters arguments readonly


【解决方案1】:

例如:

public struct Test
{
    public int Value;
    public void SetValue(int value) => Value = value;
}
public static void Method(in Test test)
{
     test.SetValue(5);
     Console.WriteLine(test.Value); // 0
 }

这将编译得很好。如果我正确理解这种情况,则不会在调用构造函数时创建副本,而是在调用任何可能改变值的方法时创建副本。

将结构设置为只读将阻止调用任何变异方法,因此将避免隐藏副本。

还有good arguments for why mutable structs are evil,所以我主张只将所有结构设为只读。即

public readonly struct Test
{
    public int Value { get; }
    public Test(int v) => Value = v;
    // Any "mutating" method should create a copy instead
    public Test WithValue(int v) => new Test(v); 
}

【讨论】:

  • 但是为什么编译器会生成一个防御性副本呢?如果“in”说“这不会被修改”,那有什么意义呢?仅适用于像您的示例这样的情况吗?
  • @Firld 编译器必须强制执行“这不会被修改”声明。如果它不能证明它不会被修改,它必须创建一个防御性副本。如果该结构被标记为只读,则证明是微不足道的。但是证明某些东西可能很困难,编译器很可能只是在任何不平凡的情况下创建一个防御性副本。
猜你喜欢
  • 2021-04-30
  • 1970-01-01
  • 1970-01-01
  • 2021-08-16
  • 1970-01-01
  • 2020-10-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多