我知道在.Net中,可变结构体/值类型被认为是“邪恶”的。那么为什么还可以创建它们呢?有哪些好的用途可以证明将这个特性添加到CLR中是合理的呢?
我知道在.Net中,可变结构体/值类型被认为是“邪恶”的。那么为什么还可以创建它们呢?有哪些好的用途可以证明将这个特性添加到CLR中是合理的呢?
namespace StructEx
{
public struct AStruct
{
public int AnInt { get; internal set; }
}
public class AStructBuilder
{
public AStruct BuildStruct(int anInt)
{
return new AStruct { AnInt = anInt };
}
}
}
AStruct
也可以用构造函数来设置readonly
字段(这不会改变API)- 但我明白你的意思。 - Marc GravellAStruct
。 - Davy8StringBuilder
,但是无法想出一个有趣的东西来构建。我同意,对于我的结构体,我使用readonly
并从构造函数初始化。我没有使用上述模式。 - Matt Ellenstruct myStruct {public int v; ... other stuff...}; class myClass {public int v; ... other stuff...}; interface ISample { void useStructByValue(myStruct z); void useStructByReference(ref myStruct z); void useClassByValue(myClass z); void useClassByReference(ref myClass z); }并考虑以下方法:
void test(myStruct struct1, myStruct struct2, myClass class1, myClass class2, ISample munger) { for(int i=0; i < 5; i++) { munger.useStructByValue(struct1); // S1 munger.useStructByReference(ref struct2); // S2 munger.useClassByvalue(class1); // S3 munger.useClassByReference(ref class2); // S4 } }假设只要munger不使用任何不安全代码,哪些传入的项可能受到这四个语句的影响?我认为即使没有看到struct1的整个定义或者munger的任何部分实现,也可以确定struct1.v不会被任何一个语句改变,保证。struct2.v可能会被S2改变,但不会被其他语句改变,同样保证。然而,class1.v和class2.v的值可能会被任何一个语句改变;唯一知道哪个语句可以改变class1.v或class2.v的方法是检查每个现在或将来实现ISample接口的类型的代码。
List<myStruct> myList; ... myStruct tempStruct = myList[1]; tempStrict.v = 5; myList[1] = tempStruct;虽然不是线程安全的,但语义清晰明了。将myStruct替换为myClass,则确定性变得模糊。如果列表中的每个项目都有一个未共享的myClass实例,那么可以简单地使用
myList [1] .v = 5;
。然而,确定列表项是否具有未共享的myClass实例几乎是不可能的。如果有人试图将myList [1]
的值复制到myList [0]
中并且写入myList [1] .v
会影响到myList [0] .v
,这样的语句虽然可用但会导致问题。结构体则不会存在这样的问题。