суббота, 19 сентября 2009 г.

Tuple as value type

There is new  type in .NET BCL - Tuple.  What is it is explained in the article CLR Inside Out: Building Tuple. The BCL team has decided it to be a reference  type. The reason is well motivated but I think there are cases when having a tuple as a valuetype is beneficial. One of the such case is when you use a tuple as a key in a dictionary. Creating an object in the heap just to get a value from the dictionary or to find out whether it exists would be.. at least not proper use of GC. Especialy when you do it in a tight loop.

Honestly, using keys in dictionaries were the only reason I have used tuples before. Now not to interfere with with Tuple from BCL and to conform to it I have renamed my value type Tuple to TupleValue, properties Value1, Value to Item1, Item2, factory method New to Create.

Implementation is trivial. The only important detail is IEquatable<T>.  A value type not implementing this interface is boxed when used as a key in a dictionary.

 

using System;
using System.Collections.Generic;

namespace Omari
{
public static class TupleValue
{
public static TupleValue<TItem1, TItem2> Create<TItem1, TItem2>(TItem1 item1, TItem2 item2)
{
return new TupleValue<TItem1, TItem2>(item1, item2);
}

public static TupleValue<TItem1, TItem2, TItem3> Create<TItem1, TItem2, TItem3>(TItem1 item1, TItem2 item2, TItem3 item3)
{
return new TupleValue<TItem1, TItem2, TItem3>(item1, item2, item3);
}
}

public struct TupleValue<TItem1, TItem2> : IEquatable<TupleValue<TItem1, TItem2>>
{
TItem1 _item1;
TItem2 _item2;

public TItem1 Item1 { get { return _item1; } }
public TItem2 Item2 { get { return _item2; } }

public TupleValue(TItem1 item1, TItem2 item2)
{
_item1 = item1;
_item2 = item2;
}

public bool Equals(TupleValue<TItem1, TItem2> other)
{
return EqualityComparer<TItem1>.Default.Equals(_item1, other.Item1) &&
EqualityComparer<TItem2>.Default.Equals(_item2, other.Item2);
}

public override bool Equals(object obj)
{
if (obj.GetType() != typeof(TupleValue<TItem1, TItem2>))
return false;

return Equals((TupleValue<TItem1, TItem2>)obj);
}

public override int GetHashCode()
{
return EqualityComparer<TItem1>.Default.GetHashCode(_item1) ^
EqualityComparer<TItem2>.Default.GetHashCode(_item2);
}
}

public struct TupleValue<TItem1, TItem2, TItem3> : IEquatable<TupleValue<TItem1, TItem2, TItem3>>
{
TItem1 _item1;
TItem2 _item2;
TItem3 _item3;

public TItem1 Item1 { get { return _item1; } }
public TItem2 Item2 { get { return _item2; } }
public TItem3 Item3 { get { return _item3; } }

public TupleValue(TItem1 item1, TItem2 item2, TItem3 item3)
{
_item1 = item1;
_item2 = item2;
_item3 = item3;
}

public bool Equals(TupleValue<TItem1, TItem2, TItem3> other)
{
return EqualityComparer<TItem1>.Default.Equals(_item1, other.Item1) &&
EqualityComparer<TItem2>.Default.Equals(_item2, other.Item2) &&
EqualityComparer<TItem3>.Default.Equals(_item3, other.Item3);
}

public override bool Equals(object obj)
{
if (obj.GetType() != typeof(TupleValue<TItem1, TItem2, TItem3>))
return false;

return Equals((TupleValue<TItem1, TItem2, TItem3>)obj);
}

public override int GetHashCode()
{
return EqualityComparer<TItem1>.Default.GetHashCode(_item1) ^
EqualityComparer<TItem2>.Default.GetHashCode(_item2) ^
EqualityComparer<TItem3>.Default.GetHashCode(_item3);
}
}
}




2 комментария: