Структура ValueTuple изменчива только как переменная?

Я играл с ValueTuple структурировать и пытаться реализовать неизменный составной ключ. Ключ состоит из типов значений.

Я попытался сломать следующую реализацию с помощью некоторых модульных тестов, но пока безуспешно. Я что-то пропустил?

Также это просто из любопытства, я хочу добраться до ValueTupleи его ограничения до выхода.NET 4.7.

Пока мое понимание 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()));
    }
}

ошибка: невозможно изменить возвращаемое значение ImmutableKey.Key, поскольку оно не является переменной

1 ответ

Решение

Есть три случая, когда можно изменить изменяемую структуру и увидеть результат:

  • локальная переменная: MyStruct s = new MyStruct(); s.Prop = 4;
  • поле другого типа: class MyType { public MyStruct S;} ... myType.S.Prop = 4;
  • элемент массива: MyStruct[] myArray =...; myArray[3].Prop = 4;,

Почему код в посте не обнаружил изменения - код использовал свойство, а не поле.

Обратите внимание, что List<MyStruct> не позволяет модификацию, потому что индексатор (this[..]) возвращает копию элемента (так как нет поддержки, возвращающей ссылку, как в C++).

Другие вопросы по тегам