Reputation: 3376
I understand that, unlike C++, it is not possible to override assignment operator (=) in C# and it is necessary to create a copy method should we want to assign the instance i1 of class C to another instance i2 (of class C).
But here come the dilemma: I have a generic class T
public class Node<T>
{
public Node<T> Next;
public Node<T> Previous;
T Content;
public Node<T>()
{
}
}
T can be a generic class like Person or can be a C# standard types like int, double... There is a need to, sometime assign (=) the value of the content T in Node with another content T. It would be nice if there were an assignment operator that could be implemented in the generic class T so that t1=t2 operation would work with generic class and standard types such as int, double... alike.
What are your suggestions since overloading assignment operator is not allowed in C#? I am looking for an elegant solution that would work for both generic classes and standard types so that my code does not have to distinguish different scenarios.
Is it possible to do that? Many thanks!
Upvotes: 2
Views: 2377
Reputation: 29274
Let me propose a slightly different structure that would allow full customization of the content type.
public class Node<T> where T : Node<T>
{
public T Next { get; set; }
public T Previous { get; set; }
}
You cannot use this class directly, but you inherit from it for your content types. For example:
public class Student : Node<Student>
{
public int ID { get; set; }
public string Name { get; set; }
public override string ToString() { return string.Format("ID={0}, Name={1}", ID, Name); }
}
Now each Student
is the contents as well as the list node at the same time. The Node<T>
class is re-usable.
Now you can add some smarts to the node class. For example:
public class Node<T> where T : Node<T>
{
public T Next { get; set; }
public T Previous { get; set; }
public bool IsRoot { get { return Previous==null; } }
public bool IsLeaf { get { return Next==null; } }
public int CountBefore { get { return IsRoot ? 0 : Previous.CountBefore+1; } }
public int CountAfter { get { return IsLeaf ? 0 : Next.CountAfter+1; } }
public T InsertAfter(T node)
{
var temp = this.Next;
this.Next=node;
if(node!=null)
{
node.Next=temp;
node.Previous=this as T;
}
if(temp!=null)
{
temp.Previous=node;
}
return node;
}
public T InsertBefore(T node)
{
var temp = this.Previous;
this.Previous=node;
if(node!=null)
{
node.Previous=temp;
node.Next=this as T;
}
if(temp!=null)
{
temp.Next=node;
}
return node;
}
}
which can be used as such:
class Program
{
static void Main(string[] args)
{
var A = new Student() { ID=101, Name="Peter" };
var B = A.InsertAfter(new Student() { ID=102, Name="John" });
var C = B.InsertBefore(new Student() { ID=103, Name="Mary" });
// [A]----[C]----[B]
// | | |
// ID 101 103 102
// Name Peter Mary John
// IsRoot true false false
// IsLeft false false true
// CountL 0 1 2
// CountR 2 1 0
}
}
Upvotes: 1
Reputation: 1271
Being that any templated class or object you create has to take a data type, you should always be able to assign one to the other. For example, when you initialize your Node<T>
, it will still have to take a data type:
Node<double> myNode = new Node<double>();
And even if you have different instances, with different data types, you can also convert them from one to the other with C#'s Convert
methods: https://msdn.microsoft.com/en-us/library/system.convert.aspx
Node<int> mySecondNode = new Node<int>();
Node<string> myThirdNode = new Node<string>();
Node<bool> myFourthNode = new Node<bool>();
myNode.Content = Convert.ToDouble(mySecondNode.Content);
myThirdNode.Content = myNode.ToString();
myFourthNode = Convert.ToBoolean(mySecondNode.Content % 2);
And so on.... Overloading operators is fantastic; but C# makes it easy for you. Also, like Bradley said, the C# libraries have a LinkedList
class, so you don't need to do all the heavy lifting. Check it out here:
https://msdn.microsoft.com/en-us/library/he2s3bh7(v=vs.110).aspx
Upvotes: 1
Reputation: 61379
You can always assign a variable of a given type to another variable of that type.
In other words, writing:
public void Reassign(T source)
{
Content = source;
}
will always work. You do have to deal with many types being reference types so all that is assigned is the reference. If you want to force value copying you would need to add some generic type constraints (ICloneable
or similar would work, but you would then need wrappers for the common .NET types).
In other words, if you did:
public class Node<T> where T : ICloneable
You could then write
public void Assign(T source)
{
Content = source.Clone();
}
Or if you don't need to recursively value-copy there is always Object.MemberwiseClone
:
public void Assign(T source)
{
Content = source.MemberwiseClone();
}
Also, in case you are not aware, .NET already has a doubly linked list in the LinkedList<T>
class.
Upvotes: 4
Reputation: 14017
You can't overload the assignment operator, but you can create explicit or implicit type conversion operators. That makes overloading assignments in your case unnecessary:
public static implicit operator Node<T>(T value) {
Node<T> node = new Node<T>();
node.Content = value;
return node;
}
That makes this assignment perfectly possible:
int value = 1;
Node<int> node = value;
If you replace implicit
by explicit
, you need an explicit type conversion:
int value = 1;
Node<int> node = (Node<T>)value;
You can also create a conversion in the opposite direction:
public static implicit operator T(Node<T> node) {
return node.Content;
}
So you can assign the node to a value:
Node<int> node = new Node<int>();
int value = node;
You can also convert to different node types:
public static implicit operator Node<double>(Node<T> node) {
Node<double> destinationNode = new Node<double>();
destinationNode.Content = Convert.ToDouble(node.Content);
return destinationNode;
}
That is pretty much what you need.
Upvotes: 1