Tuple for .Net 3.5
Still working in .Net 3.5 and you want to take advantage of the new .Net 4.0 Tuple? Well this is probably the best you'll be able to get in .Net 3.5. The code below will give you up to 10 items in a Tuple...if you find yourself needing more than that, then it's probably time to consider making a real class.When should I use a Tuple?
Good Idea
Use tuples to return interfaces that are related:
public interface ICustomerRetriever
{
//Item 1: Summary Customer information, Item 2: Detailed customer information
Tuple<ICustomer, ICustomerDetail> GetCustomer(Guid customerId);
//Item 1: Customer's first name, Item 2: Customer's last name
Tuple<string, string> GetCustomerName(Guid customerId);
//Sometimes key value pair makes more sense. So don't
//immediately use Tuples...consider what makes the most sense...
//Key: Id of parent customer, Value: Summary information of Parent Customer
KeyValuePair<Guid, ICustomer> GetParentCustomer(Guid childCustomerId);
}
Use tuples in your unit tests that leverage mocks:
TestClass
public class when_checking_to_see_if_user_can_save_customer : IRoleRetriever
{
//entity we are trying to test
private ICustomerSaver _customerSaver;
//constructor
public when_checking_to_see_if_user_can_save_customer()
{
//new up the ICustomerSaver and inject the unit test as the mock for IRoleRetriever
//the constructor for CustomerSaver is:
//CustomerSaver(IRoleRetriever roleRetriever)
_customerSaver = new CustomerSaver(this);
}
TestMethod
public void should_delegate_role_check_to_IRoleRetriever()
{
int userId = 12;
int companyId = 17;
string customerFirstName = "John";
string customerLastName = "Doe";
//The SaveCustomer method would ensure that
//the user has access to save a customer
//given the role "CanSaveCustomer". Inside the
//SaveCustomer method, a call is made to the
//RoleRetriver passing in the userId and the companyId.
//This unit test ensures that the userId and companyId
//are not inadvertently flipped when calling
//RoleRetriever.RoleExists(userId, companyId, "CanSaveCustomer")
_customerSaver.SaveCustomer(userId,
companyId,
customerFirstName,
customerLastName);
//these assertions would fail if the SaveCustomer method was
//calling _roleRetriever.RoleExists(companyId, userId, "CanSaveCustomer")
//as opposed to _roleRetriever.RoleExists(userId, companyId, "CanSaveCustomer")
Assert.AreEqual(12, _tupleForRoleExists.Item1);
Assert.AreEqual(17, _tupleForRoleExists.Item2);
Assert.AreEqual("CanSaveCustomer", _tupleForRoleExists.Item3);
}
//this tuple is updated every time the RoleExists method is
//called via the IRoleRetriever method
private Tuple<int, int, string> _tupleForRoleExists =
new Tuple<int, int, string>();
//this is the mocked role retriever method that just records what was passed in
bool IRoleRetriever.RoleExists(int userId, int companyId, string role)
{
_tupleForRoleExists.Item1 = userId;
_tupleForRoleExists.Item2 = companyId;
_tupleForRoleExists.Item3 = role;
return true;
}
}
Bad Idea
Don't use tuples cause you're lazy...
//this is a bad idea, do not do this.....
public interface ICustomerRetriever
{
//Item 1: Customer's first name, Item 2: Customer's middle name
//Item 3: Customer's last name, Item 4: Date of Birth
Tuple<string, string, string, DateTime> GetCustomer(Guid customerId);
}
Source Code for Tuple
public class Tuple<T>
{
public Tuple(T item1)
{
Item1 = item1;
}
public T Item1 { get; set; }
}
public class Tuple<T, T2>
: Tuple<T>
{
public Tuple(T item1, T2 item2)
: base(item1)
{
Item2 = item2;
}
public T2 Item2 { get; set; }
}
public class Tuple<T, T2, T3>
: Tuple<T, T2>
{
public Tuple(T item1, T2 item2, T3 item3)
: base(item1, item2)
{
Item3 = item3;
}
public T3 Item3 { get; set; }
}
public class Tuple<T, T2, T3, T4>
: Tuple<T, T2, T3>
{
public Tuple(T item1, T2 item2, T3 item3, T4 item4)
: base(item1, item2, item3)
{
Item4 = item4;
}
public T4 Item4 { get; set; }
}
public class Tuple<T, T2, T3, T4, T5>
: Tuple<T, T2, T3, T4>
{
public Tuple(T item1, T2 item2, T3 item3, T4 item4, T5 item5)
: base(item1, item2, item3, item4)
{
Item5 = item5;
}
public T5 Item5 { get; set; }
}
public class Tuple<T, T2, T3, T4, T5, T6>
: Tuple<T, T2, T3, T4, T5>
{
public Tuple(T item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6)
: base(item1, item2, item3, item4, item5)
{
Item6 = item6;
}
public T6 Item6 { get; set; }
}
public class Tuple<T, T2, T3, T4, T5, T6, T7>
: Tuple<T, T2, T3, T4, T5, T6>
{
public Tuple(T item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7)
: base(item1, item2, item3, item4, item5, item6)
{
Item7 = item7;
}
public T7 Item7 { get; set; }
}
public class Tuple<T, T2, T3, T4, T5, T6, T7, T8>
: Tuple<T, T2, T3, T4, T5, T6, T7>
{
public Tuple(T item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, T8 item8)
: base(item1, item2, item3, item4, item5, item6, item7)
{
Item8 = item8;
}
public T8 Item8 { get; set; }
}
public class Tuple<T, T2, T3, T4, T5, T6, T7, T8, T9>
: Tuple<T, T2, T3, T4, T5, T6, T7, T8>
{
public Tuple(T item1, T2 item2, T3 item3, T4 item4,
T5 item5, T6 item6, T7 item7, T8 item8, T9 item9)
: base(item1, item2, item3, item4, item5, item6, item7, item8)
{
Item9 = item9;
}
public T9 Item9 { get; set; }
}
public class Tuple<T, T2, T3, T4, T5, T6, T7, T8, T9, T10>
: Tuple<T, T2, T3, T4, T5, T6, T7, T8, T9>
{
public Tuple(T item1, T2 item2, T3 item3, T4 item4,
T5 item5, T6 item6, T7 item7, T8 item8, T9 item9, T10 item10)
: base(item1, item2, item3, item4, item5, item6, item7, item8, item9)
{
Item10 = item10;
}
public T10 Item10 { get; set; }
}
Written: 3/28/2010