匿名类型的非只读替代方案

Sup*_*est 32 c# struct anonymous-types data-structures

在C#中,匿名类型可以如下:

method doStuff(){
     var myVar = new {
         a = false, 
         b = true
     }

     if (myVar.a) 
     {
         // Do stuff             
     }
}
Run Code Online (Sandbox Code Playgroud)

但是,以下内容将无法编译:

method doStuff(){
     var myVar = new {
         a = false, 
         b = true
     }

     if (myVar.a) 
     {
         myVar.b = true;
     }
}
Run Code Online (Sandbox Code Playgroud)

这是因为myVar的字段是只读的,无法分配.似乎想做一些像后者相当普遍的事情; 也许我见过的最好的解决方案就是在方法之外定义一个结构.

但是,真的没有办法让上面的块工作吗?困扰我的原因是,myVar是这个字段的局部变量,所以它似乎只应该在使用它的方法中引用.此外,需要将struct放在方法之外可以使对象的声明远离其使用,特别是在长方法中.

换句话说,有没有匿名类型的替代方法,这将允许我定义这样的"结构"(我意识到结构存在于C#中,必须在方法之外定义)而不使其只读?如果不是,想要这样做是否存在根本性的错误,我应该采用不同的方法吗?

Jon*_*eet 34

不,你必须创建自己的类或结构来执行此操作(如果你希望它是可变的,最好是一个类 - 可变结构是可怕的).

如果您不关心Equals/ ToString/ GetHashCode实现,那很容易:

public class MyClass {
    public bool Foo { get; set; }
    public bool Bar { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

(出于各种原因,我仍然使用属性而不是字段.)

就个人而言,我通常发现自己想要一个不可变类型,我可以在方法之间传递等等 - 我想要一个现有匿名类型功能的命名版本......

  • 我发现自己想要的是用于声明具有特定字段的结构的快速简写,以及将这些字段作为参数的自动生成的构造函数.注意,顺便说一句,如果一个struct没有任何修改`this`的成员函数或访问外部权限的属性,*一个"不可变"结构和一个"可变"结构将无法区分任何不直接的代码试图修改其字段*.我可以看到反对尝试修改结构字段的参数,如果一个人不知道自己在做什么,但这不是结构禁止这种修改的论据. (2认同)
  • @supercat:我已经看到了由可变结构引起的足够的问题,以避免它们在除了最特殊的情况之外的所有情况.这种情况确实存在,但我发现它们很少见.我怀疑,鉴于你的答案,我们必须同意不同意可变结构是否是一个好主意. (2认同)
  • @supercat - 虽然您可能知道可变结构的所有可能缺陷,但是您能保证维护或(如果公开)使用您的代码的每个开发人员都会知道这些吗?虽然我不相信编码到最低的共同点,但可变结构与我首选的"成功陷阱"相反. (2认同)

Eri*_*ert 25

有没有匿名类型的替代方法,这将允许我简明地定义这样一个简单的"记录"类型而不使其只读?

不,你必须做出名义上的类型.

如果不是,想要这样做有什么根本性的错误吗?

不,这是我们之前考虑过的一个合理的功能.

我注意到在Visual Basic中,如果您希望匿名类型可变的.

关于可变匿名类型的唯一真正"根本错误"的是,将一个用作哈希键是危险的.我们设计了匿名类型,其假设是:(1)您将在LINQ查询理解中将它们用作等值连接中的键,以及(2)在LINQ到对象和其他实现中,连接将使用哈希表实现.因此,匿名类型应该用作散列键,并且可变散列键是危险的.

在Visual Basic中,GetHashCode实现不使用匿名类型的可变字段中的任何信息.虽然这是一个合理的妥协,但我们只是决定在C#中额外的复杂性并不值得付出努力.


Kee*_*ker 5

在C#7中,我们可以利用命名元组来完成技巧:

(bool a, bool b) myVar = (false, true);

if (myVar.a)
{
    myVar.b = true;
}
Run Code Online (Sandbox Code Playgroud)