简体   繁体   English

C#中的赋值运算符

[英]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). 我理解,与C ++不同,不可能在C#中覆盖赋值运算符(=),如果我们想要将类C的实例i1分配给另一个实例i2(C类),则必须创建一个复制方法。

But here come the dilemma: I have a generic class T 但是这里陷入了两难境地:我有一个通用的类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. T可以是类似Person的泛型类,也可以是C#标准类型,如int,double ...有时需要在Node中使用另一个内容T赋值(=)内容T的值。这样会很好如果有一个赋值运算符可以在泛型类T中实现,那么t1 = t2操作将适用于泛型类和标准类型,如int,double ......等。

What are your suggestions since overloading assignment operator is not allowed in C#? 你有什么建议,因为在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! 非常感谢!

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). 如果你想强制复制值,你需要添加一些泛型类型约束( ICloneable或类似的工作,但你需要包装常见的.NET类型)。

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 : 或者,如果您不需要递归值复制,则总是存在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. 此外,如果你不知道,.NET已经在LinkedList<T>类中有一个双向链表。

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: 如果用explicit替换implicit explicit ,则需要显式类型转换:

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. 这几乎是你所需要的。

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<T> ,它仍然需要采用数据类型:

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 即使您有不同的实例,使用不同的数据类型,您也可以使用C#的Convert方法将它们从一个转换为另一个: 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. 但是C#让你很容易。 Also, like Bradley said, the C# libraries have a LinkedList class, so you don't need to do all the heavy lifting. 另外,像Bradley所说,C#库有一个LinkedList类,所以你不需要做所有繁重的工作。 Check it out here: https://msdn.microsoft.com/en-us/library/he2s3bh7(v=vs.110).aspx 请在此处查看: https//msdn.microsoft.com/en-us/library/he2s3bh7(v = vs.110).aspx

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. 现在每个Student是内容和列表节点。 The Node<T> class is re-usable. Node<T>类是可重用的。

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

    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM