ValueTuple 结构是否只能作为变量可变?
is the ValueTuple structure only mutable as variable?
我尝试使用 ValueTuple
结构并尝试实现一个不可变的组合键。键由值类型组成。
我试图通过一些单元测试来破坏以下实现,但到目前为止没有成功。我错过了什么吗?
此外,这只是出于好奇,我想在 .NET 4.7 发布之前了解 ValueTuple
s 和它的局限性。
到目前为止,我对 ValueTuple
的理解是它仅作为变量可变,而不是作为字段或 属性。虽然不确定这里的“可变”是什么意思。改变 ValueTuple
实例 实际上 创建一个新的 ValueTuple
(就像众所周知字符串是“不可变的”但 实际上 引用类型)?
from
System.ValueTuple
isn't only a struct
, it's a mutable one, and one has to be careful when using them as such. Think what happens when a class holds a System.ValueTuple
as a field.
这里是我的实现和测试
public interface IHaveCompositeKey
{
(Guid id, string name) Key { get; }
}
public class ImmutableKey : IHaveCompositeKey
{
public (Guid id, string name) Key { get; }
public ImmutableKey((Guid id, string name) key) => Key = key;
public override int GetHashCode() => Key.GetHashCode();
public override bool Equals(object obj)
{
var a = obj as ImmutableKey;
return a != null && Key.Equals(a.Key);
}
}
[TestFixture]
public class KeyTests
{
[Test]
public void Test1() // passes
{
var key = (Guid.NewGuid(), "Foo");
var a = new ImmutableKey(key);
var b = new ImmutableKey(key);
Assert.IsTrue(a.Equals(b));
Assert.IsTrue(a.GetHashCode().Equals(b.GetHashCode()));
}
[Test]
public void Test2() // passes
{
(Guid id, string name) key = (Guid.NewGuid(), "Foo");
var a = new ImmutableKey(key);
key.name = "Bar"; // mutable
var b = new ImmutableKey(key);
Assert.IsFalse(a.Equals(b));
Assert.IsFalse(a.GetHashCode().Equals(b.GetHashCode()));
}
[Test]
public void Test3() // does not compile
{
var key = (Guid.NewGuid(), "Foo");
var a = new ImmutableKey(key);
// compilation error
a.Key.name = "Bar"; // immutable
var b = new ImmutableKey(a.Key);
Assert.IsFalse(a.Equals(b));
Assert.IsFalse(a.GetHashCode().Equals(b.GetHashCode()));
}
}
error: Cannot modify the return value of 'ImmutableKey.Key' because it is not a variable
可以在三种情况下更改可变结构并查看结果:
- 局部变量:
MyStruct s = new MyStruct(); s.Prop = 4;
- 字段 另一种类型:
class MyType { public MyStruct S;} ... myType.S.Prop = 4;
- 数组的元素:
MyStruct[] myArray =...; myArray[3].Prop = 4;
。
为什么 post 中的代码未检测到更改 - 使用的代码 属性 而不是字段。
请注意,List<MyStruct>
不允许修改,因为索引器 (this[..]
) returns 项目的副本(因为不支持像 C++ 那样返回引用)。
我尝试使用 ValueTuple
结构并尝试实现一个不可变的组合键。键由值类型组成。
我试图通过一些单元测试来破坏以下实现,但到目前为止没有成功。我错过了什么吗?
此外,这只是出于好奇,我想在 .NET 4.7 发布之前了解 ValueTuple
s 和它的局限性。
到目前为止,我对 ValueTuple
的理解是它仅作为变量可变,而不是作为字段或 属性。虽然不确定这里的“可变”是什么意思。改变 ValueTuple
实例 实际上 创建一个新的 ValueTuple
(就像众所周知字符串是“不可变的”但 实际上 引用类型)?
from
System.ValueTuple
isn't only astruct
, it's a mutable one, and one has to be careful when using them as such. Think what happens when a class holds aSystem.ValueTuple
as a field.
这里是我的实现和测试
public interface IHaveCompositeKey
{
(Guid id, string name) Key { get; }
}
public class ImmutableKey : IHaveCompositeKey
{
public (Guid id, string name) Key { get; }
public ImmutableKey((Guid id, string name) key) => Key = key;
public override int GetHashCode() => Key.GetHashCode();
public override bool Equals(object obj)
{
var a = obj as ImmutableKey;
return a != null && Key.Equals(a.Key);
}
}
[TestFixture]
public class KeyTests
{
[Test]
public void Test1() // passes
{
var key = (Guid.NewGuid(), "Foo");
var a = new ImmutableKey(key);
var b = new ImmutableKey(key);
Assert.IsTrue(a.Equals(b));
Assert.IsTrue(a.GetHashCode().Equals(b.GetHashCode()));
}
[Test]
public void Test2() // passes
{
(Guid id, string name) key = (Guid.NewGuid(), "Foo");
var a = new ImmutableKey(key);
key.name = "Bar"; // mutable
var b = new ImmutableKey(key);
Assert.IsFalse(a.Equals(b));
Assert.IsFalse(a.GetHashCode().Equals(b.GetHashCode()));
}
[Test]
public void Test3() // does not compile
{
var key = (Guid.NewGuid(), "Foo");
var a = new ImmutableKey(key);
// compilation error
a.Key.name = "Bar"; // immutable
var b = new ImmutableKey(a.Key);
Assert.IsFalse(a.Equals(b));
Assert.IsFalse(a.GetHashCode().Equals(b.GetHashCode()));
}
}
error: Cannot modify the return value of 'ImmutableKey.Key' because it is not a variable
可以在三种情况下更改可变结构并查看结果:
- 局部变量:
MyStruct s = new MyStruct(); s.Prop = 4;
- 字段 另一种类型:
class MyType { public MyStruct S;} ... myType.S.Prop = 4;
- 数组的元素:
MyStruct[] myArray =...; myArray[3].Prop = 4;
。
为什么 post 中的代码未检测到更改 - 使用的代码 属性 而不是字段。
请注意,List<MyStruct>
不允许修改,因为索引器 (this[..]
) returns 项目的副本(因为不支持像 C++ 那样返回引用)。