ValueTuple结构只能作为变量变化吗?

Mic*_*ing 4 c# immutability mutability valuetuple

我玩弄了ValueTuple结构并试图实现一个不可变的复合键.密钥由值类型组成.

我尝试用一​​些单元测试打破以下实现,到目前为止还没有成功.我错过了什么吗?

这也只是出于好奇,我想ValueTuple在.NET 4.7发布之前得到s和它的局限性.

到目前为止,我对a的理解ValueTuple是它只作为变量而不是作为字段或属性变化.不知道"可变"在这里意味着什么.更改ValueTuple实例实际上是否创建了一个新的ValueTuple(就像它的常识一样,字符串是"不可变的"但实际上是引用类型)?

这个答案

System.ValueTuple不仅是一个struct,它是一个可变的,并且在使用它们时必须要小心.想想当一个班级System.ValueTuple作为一个领域时会发生什么.

在这里我的实施和测试

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()));
    }
}
Run Code Online (Sandbox Code Playgroud)

错误:无法修改'ImmutableKey.Key'的返回值,因为它不是变量

Ale*_*kov 6

有三种情况可以改变可变结构并看到结果:

  • 局部变量: MyStruct s = new MyStruct(); s.Prop = 4;
  • 另一种类型的领域:class MyType { public MyStruct S;} ... myType.S.Prop = 4;
  • 数组元素:MyStruct[] myArray =...; myArray[3].Prop = 4;.

为什么帖子中的代码没有检测到更改 - 代码使用的属性而不是字段.

请注意,List<MyStruct>不允许修改,因为indexer(this[..])返回项的副本(因为没有像C++那样的支持返回引用).