I played around with the ValueTuple
structure and tried to implement an immutable composite key. The key is composed of value types.
I tried to break the following implementation with some unit tests, so far without success. Am I missing something?
Also this is just out of curiosity, I want to get to ValueTuple
s and it's limitations before the release of .NET 4.7.
So far my understanding of a ValueTuple
is that it is only mutable as a variable but not as a field or property. Not sure what "mutable" means here though. Does altering a ValueTuple
instance actually create a new ValueTuple
(like it's common knowledge that strings are "immutable" but actually reference types)?
from this answer
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.
Here my implementation and tests
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
There are three cases when one can change mutable struct and see result:
MyStruct s = new MyStruct(); s.Prop = 4;
class MyType { public MyStruct S;} ... myType.S.Prop = 4;
MyStruct[] myArray =...; myArray[3].Prop = 4;
. Why code in the post did not detect change - code used property and not a field.
Note that List<MyStruct>
does not allow modification because indexer (this[..]
) returns copy of an item (as there is no support returning reference like C++ does).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With