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

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

method doStuff(){ var myVar = new { a = false, b = true } if (myVar.a) { // Do stuff } } 

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

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

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

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

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

不,你必须创建自己的类或结构来做这个(如果你希望它是可变的,最好是一个类 – 可变结构是可怕的)。

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

 public class MyClass { public bool Foo { get; set; } public bool Bar { get; set; } } 

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

我个人通常发现自己想要一个我可以在方法之间传递的不可变类型 – 我想要一个现有匿名类型function的命名版本…

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

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

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

不,这是我们之前考虑过的一个合理的function。

我注意到在Visual Basic中,如果你想要它们,匿名类型可变的。

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

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

您将无法获得良好的初始化语法,但.NET 4中引入的ExpandoObject类将作为可行的解决方案。

 dynamic eo = new ExpandoObject(); eo.SomeIntValue = 5; eo.SomeIntValue = 10; // works fine 

对于上述类型的操作,您应该定义自己的可变STRUCT 。 可变结构可能会让像Eric Lippert这样的编译器编写者头疼,并且.net处理它们有一些不幸的限制,但仍然是可变“普通旧数据”结构的语义(所有字段都是公共的结构,唯一的结构)写this公共函数是构造函数,或者只是从构造函数中调用的)提供了比通过类实现的更清晰的语义。

例如,请考虑以下事项:

 struct Foo {
   public int bar; 
   ...其他的东西;
 }
 int test(Action  proc1,Action  proc2)
 {
   foo myFoos [] = new Foo [100];
   PROC1(myFoos);
   myFoos [4] .bar = 9;
   PROC2(myFoos [4]);  //按值传递
   return myFoos [4] .bar;
 }

假设没有不安全的代码,并且可以调用传入的委托并在有限的时间内返回, test()返回什么? 事实上, Foo是一个带有公共字段bar的结构,足以回答这个问题:它将返回9,无论Foo声明中出现什么,并且无论proc1proc2中传递了什么函数。 如果Foo是一个类,则必须检查存在或将要存在的每个ActionAction ,以了解test()将返回什么。 确定Foo是具有公共字段bar的结构似乎比检查可能传入的所有过去和未来函数要容易得多。

修改this结构方法在.net中处理得特别差,因此如果需要使用方法来修改结构,那么使用这些模式之一几乎肯定更好:

   myStruct = myStruct.ModifiedInSomeFashion(...);  //方法#1
   myStructType.ModifyInSomeFashion(ref myStruct,...);  //方法#2

比模式:

   myStruct.ModifyInSomeFashion(...);

如果使用上述方法对结构修改模式进行修改,则可变结构的优点是允许代码比不可变结构或不可变类更高效,更易于阅读,并且比可变类更不容易出错。 对于表示值聚合的事物,在它们包含的值之外没有标识,可变类类型通常是最糟糕的表示。

在C#7中,我们可以利用命名元组来实现这一目的:

 (bool a, bool b) myVar = (false, true); if (myVar.a) { myVar.b = true; }