C# C语言中的赋值运算符# 我明白,与C++不同,在C语言中不可能重写赋值操作符(=),如果要把C类的实例I1分配给另一个实例I2(C类),则需要创建一个复制方法。p>

C# C语言中的赋值运算符# 我明白,与C++不同,在C语言中不可能重写赋值操作符(=),如果要把C类的实例I1分配给另一个实例I2(C类),则需要创建一个复制方法。p>,c#,generics,C#,Generics,但现在面临的困境是: 我有一个通用类T public class Node<T> { public Node<T> Next; public Node<T> Previous; T Content; public Node<T>() { } } 公共类节点 { 公共节点下一步; 公共节点前向; T含量; 公共节点() { } } T可以是Person之类的泛型类,也可以是int、double等C#标准类型。。。有时需要

但现在面临的困境是: 我有一个通用类T

public class Node<T>
{
  public Node<T> Next;
  public Node<T> Previous;
  T Content;

  public Node<T>()
  {
  }
}
公共类节点
{
公共节点下一步;
公共节点前向;
T含量;
公共节点()
{
}
}
T可以是Person之类的泛型类,也可以是int、double等C#标准类型。。。有时需要将(=)节点中内容T的值分配给另一个内容T。如果有一个赋值运算符可以在泛型类T中实现,那么t1=t2操作可以处理泛型类和标准类型,如int、double。。。一模一样

由于C#中不允许重载赋值运算符,您有什么建议?我正在寻找一个优雅的解决方案,它既适用于泛型类,也适用于标准类型,这样我的代码就不必区分不同的场景

有可能吗?非常感谢

您始终可以将给定类型的变量分配给该类型的另一个变量

换句话说,写作:

public void Reassign(T source)
{
    Content = source;
}
我会一直工作的。您必须处理许多属于引用类型的类型,因此分配的只是引用。如果要强制复制值,则需要添加一些泛型类型约束(
ICloneable
或类似的约束可以工作,但是您需要为常见的.NET类型添加包装器)

换句话说,如果你这样做了:

public class Node<T> where T : ICloneable
或者,如果不需要递归值复制,则始终存在
对象。MemberwiseClone

public void Assign(T source)
{
    Content = source.MemberwiseClone();
}

另外,如果您不知道,.NET在类中已经有一个双链接列表。

您不能重载赋值运算符,但可以创建显式或隐式类型转换运算符。这使得您的案例中的重载分配变得不必要:

public static implicit operator Node<T>(T value) {
    Node<T> node = new Node<T>();
    node.Content = value;
    return node;
}
也可以在相反方向创建转换:

public static implicit operator T(Node<T> node) {
    return node.Content;
}
公共静态隐式运算符T(节点){
返回节点内容;
}
因此,可以将节点指定给一个值:

Node<int> node = new Node<int>();
int value = node;
Node节点=新节点();
int值=节点;
您还可以转换为不同的节点类型:

public static implicit operator Node<double>(Node<T> node) {
    Node<double> destinationNode = new Node<double>();
    destinationNode.Content = Convert.ToDouble(node.Content);
    return destinationNode;
}
公共静态隐式运算符节点(节点){
Node destinationNode=新节点();
destinationNode.Content=Convert.ToDouble(node.Content);
返回destinationNode;
}

这正是您所需要的。

由于您创建的任何模板化类或对象都必须采用数据类型,因此您应该始终能够将一种类型分配给另一种类型。例如,当您初始化
节点时,它仍然必须采用以下数据类型:

Node<double> myNode = new Node<double>();
等等。。。。重载操作符是非常棒的;但C#让你很容易。此外,正如布拉德利所说,C#库有一个
LinkedList
类,因此您不需要做所有繁重的工作。在这里查看:
让我提出一种稍微不同的结构,允许完全定制内容类型

public class Node<T> where T : Node<T>
{
    public T Next { get; set; }
    public T Previous { get; set; }
}
可以这样使用:

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

    }
}

在C#中,“将类C的实例i1分配给类C的另一个实例i2”是非常罕见和奇怪的。在C#中,我们将有一个可重新绑定的引用
r
到class
C
,并将
C
的一个新实例分配到
r
。在C#中,如果
T
是一个类,
T Content
只能作为一个引用。而C#引用是可重新绑定的。在
C#
中有用于此目的的克隆机制。为什么
this.Content=other.Content
不适合您?你能解释一下吗?另外,考虑使用内置的代码>链接键> /CODE >类型。谢谢,布拉德利。我想我有点明白你的建议,但我得承认我还不太清楚。(我自己的限制)你能详细说明一下如何强制复制内容吗?我只知道linkedlist类存在于.Net中,但树也存在吗?在树中,当我们删除节点时,在节点同时具有左分支和右分支的场景中,需要找到合适的叶,将其复制到我们希望删除的节点,然后删除叶。这就是为什么我认为引用可能不起作用的原因。@user1205746不,它仍然适用于引用复制(也许您可以详细说明引用类型的混淆之处?把它们想象成指针)。不过,我还是会详细说明复制的价值。谢谢!如果说它仍然可以工作,你是说即使我删除了叶子,引用仍然可以工作,因为有另一个“指针”指向“已删除”叶子的内容,垃圾收集器会保留它吗?在这种情况下,消耗的内存应该增加一倍,因为应该删除的不一定会被删除?您可以在C#中了解有关BST的更多信息:@user1205746在您的树中,假设当前对正在死亡的叶的唯一引用在父节点中,而对“T”实例的唯一引用在叶中。如果您只是将父-子引用分配给任何新叶,则该叶的引用计数将变为0,并且它将被垃圾收集,这将导致“T”的实例计数变为0并被收集。然而,如果您想保存“T”的实例,您可以将该引用分配给某个对象(现在为引用计数2),因此当叶死亡时,其引用计数为oneThanks,Sefe。如果T是一个类,假设Person有3个属性,ID,FirstName,LastName。你会如何分配?这个答案虽然正确,但似乎没有解决实际问题。
Node<double> myNode = new Node<double>();
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);
public class Node<T> where T : Node<T>
{
    public T Next { get; set; }
    public T Previous { get; set; }
}
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); }
}
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;
    }
}
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

    }
}