Структура 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++).