如果不确切了解您要完成的工作,很难给出完整的答案,但我将从几个重要的区别开始。
首先,在 C# 中,结构/类的区别与可变性本身无关。你可以有一个不可变的类,比如这个
public class CannotBeMutated
{
private string someVal;
public CannotBeMutated(string someVal)
{
_someVal = someVal
}
public string SomeVal => _someVal;
}
还有一个可变结构,比如这个
// This is not at all idiomatic C#, please don't use this as an example
public struct MutableStruct
{
private string _someVal;
public MutableStruct(string someVal)
{
_someVal = someVal;
}
public void GetVal()
{
return _someVal
}
public void Mutate(string newVal)
{
_someVal = newVal;
}
}
使用上面的结构我可以做到这一点
var foo = new MutableStruct("Hello");
foo.mutate("GoodBye");
var bar = foo.GetVal(); // bar == "GoodBye"!
结构体和类之间的区别在于变量传递语义。当值类型的对象(例如结构)被分配给变量,作为参数传递给方法或从方法(包括属性 getter 或 setter)返回时,会在将对象传递给新对象之前制作对象的副本函数上下文。当引用类型的对象作为参数传递给方法或从方法返回时,不会进行复制,因为我们只传递了一个引用对象在内存中的位置,而不是目的。
关于 struct 'copying' 的补充说明。想象一下,你有一个结构体,它的字段是引用类型,像这样
public struct StructWithAReferenceType
{
public List<string> IAmAReferenceType {get; set;}
}
当您将此结构的实例传递给方法时,将复制对 List 的引用的副本,但不会复制基础数据。所以如果你这样做了
public void MessWithYourSruct(StructWithAReferenceType t)
{
t.IAmAReferenceType.Add("哈哈");
}
var s = new StructWithAReferenceType { IAmAReferenceType = new List()};
MessWithYourSruct(s);
s.IAmAReferenceType.Count; // 1!
// 甚至更令人不安
var s = new StructWithAReferenceType { IAmAReferenceType = new List()};
变量 t = s; // 复制 s
s.IAmAReferenceType.Add("hi");
t.IAmAReferenceType.Count; // 1!
即使复制一个结构,它的引用类型字段仍然引用内存中的相同对象。
immutable/mutable 和 struct/class 的区别有些相似,因为它们都是关于在哪里以及是否可以更改程序中对象的内容,但它们仍然非常不同。
现在回答你的问题。在您的第二个示例中,Class1 不是不可变的,因为您可以像这样改变 Struct2 的值
var foo = new Class1();
foo.Struct2 = new Struct2("a", 1);
foo.Struct2 // returns a copy of Struct2("a", 1);
foo.Struct2 = new Struct2("b", 2);
foo.Struct2 // returns a copy of Struct2("b", 2);
Struct2 是不可变的,因为无法调用代码来更改 StrVar 或 InVar 的值一次。 InStruct 同样是不可变的。但是,Array 不是不可变的。所以 InStruct 是一个可变值的不可变容器。类似于如果您有ImmutableList<List<string>>。虽然您可以保证调用代码不会将 InStruct.StrArray 的值更改为不同的数组,但您不能对调用代码更改数组中的对象的值进行任何操作。in。
最后,一些与您的示例相关的通用建议。
首先,可变结构或具有可变字段的结构是不好的。上面的例子应该指出为什么具有可变字段的结构是不好的。 Eric Lippert 本人在他的博客 here
上有一个很好的例子来说明可变结构是多么可怕
其次,对于大多数使用 C# 的开发人员来说,几乎没有理由创建用户定义的值类型(即结构)。值类型的对象存储在堆栈中,这使得对它们的内存访问非常快。引用类型的对象存储在堆上,因此访问速度较慢。但是在大量大多数 C# 程序中,磁盘 I/O、网络 I/O、序列化代码中的反射,甚至是集合的初始化和操作的时间成本都会使这种区别相形见绌.对于不编写性能关键标准库的普通开发人员来说,几乎没有理由考虑差异对性能的影响。哎呀,Java、Python、Ruby、Javascript 和许多其他语言的开发人员完全没有用户定义的值类型。通常,他们为开发人员带来的额外认知开销几乎不值得您看到任何好处。另外,请记住,无论何时将大型结构传递或分配给变量,都必须对其进行复制,这实际上可能是一个性能问题。
TL;DR 您可能不应该在代码中使用结构,而且它们与不变性没有任何关系。