user1205746
user1205746

Reputation: 3376

Assignment operator in C#

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

Answers (4)

John Alexiou
John Alexiou

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

Uchiha Itachi
Uchiha Itachi

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

BradleyDotNET
BradleyDotNET

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

Sefe
Sefe

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

Related Questions