'Inheriting C# Tuple<T, T> while adding value checks to the constructor.
I am not sure how to phrase the question better. I searched for it and did not find much of an answer, whether in Stack Overflow or elsewhere. Everything I got was how terrible the Tuple type is and how I should avoid doing that at all costs.
Anyway, the program I am working on, essentially, models a house with the rooms in it as some sort of Graph. To represent the rooms that should be adjacent to each other (and edge, or an Adjacency), I am using a Tuple<Room, Room> . However, every time I create that Tuple I go through checks to make sure the same two rooms are always in the same order. So if this was my class
public class Adjacency : Tuple<Room, Room>
{
public Adjacency(Room item1, Room item2)
{
}
}
I need Adjacency(Room1, Room2); and Adjacency(Room2, Room1); to always produce the same object. I am currently doing that by checking before I create the Tuple using Tuple.Create, but the code seems a bit of a mess at the moment and I am trying to abstract by inheriting from Tuple<Room, Room> and doing the checks in the constructor. (However since the base constructor executes first I can't find a way to do that).
The code I want to simplify/abstract is what follows, all currently in class House:
public List<Tuple<Room, Room>> Adjacencies { get; private set; }
public void PairRooms(Room r1, Room r2)
{
if(r1.UniqueID == r2.UniqueID)
throw new InvalidOperationException("Cannot pair a room with itself.");
foreach(var pair in Adjacencies)
if((r1.UniqueID == pair.Item1.UniqueID && r2.UniqueID == pair.Item2.UniqueID)
|| (r1.UniqueID == pair.Item2.UniqueID && r2.UniqueID == pair.Item1.UniqueID))
throw new Exception("Pair already paired.");
var adjacentRooms = r1.NumericID < r2.NumericID ? Tuple.Create(r1, r2) : Tuple.Create(r2, r1);
Adjacencies.Add(adjacentRooms);
Console.WriteLine($"{r1.Name}, {r2.Name} are paired");
}
public IList<Room> GetAdjacentRooms(Room room)
{
var rooms = new List<Room>();
foreach(var pair in Adjacencies)
if(pair.Item1.UniqueID == room.UniqueID)
rooms.Add(pair.Item2);
else if(pair.Item2.UniqueID == room.UniqueID)
rooms.Add(pair.Item1);
return rooms;
}
public bool AreAdjacent(Room r1, Room r2)
{
foreach(var pair in Adjacencies)
if((r1.UniqueID == pair.Item1.UniqueID && r2.UniqueID == pair.Item2.UniqueID)
|| (r1.UniqueID == pair.Item2.UniqueID && r2.UniqueID == pair.Item1.UniqueID))
return true;
return false;
}
I know the code is a mess and I am using two ID's for the objects (one is a GUID and the other is just based on a static population counter), but that's not the part I am having trouble with.
I am using the PairRooms method all over the House constructor, and the other two methods are used by algorithms operating on the house (to shuffle the rooms about and whatnot.)
Thanks for your help.
PS. would it be a viable alternative to have Tuple<Room, Room> a private property of Adjacency instead of it being the base class ?
Solution 1:[1]
A bit late. You can use a bool function and a cache bool (to avoid calling it twice) and call the base constructor, swapping the two arguments' places based on the function's return.
public class OrderConsistentSameTypeTuple<T> : Tuple<T, T>
{
public OrderConsistentSameTypeTuple(T item1, T item2) : this(item1, item2, false) { }
private OrderConsistentSameTypeTuple(T item1, T item2, bool swappedConstrArgs)
: base(
(swappedConstrArgs = swapConstrArgs(item1, item2))
? item2 : item1,
swappedConstrArgs ? item1 : item2) { }
private static bool swapConstrArgs(T item1, T item2)
{
//a true return here will swap base constructor arguments' places
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
