我理解,与C ++不同,它不可能在C#中覆盖赋值运算符(=),如果我们想要将类C的实例i1分配给另一个实例i2(类),则必须创建一个复制方法C)。
但是这里陷入了两难境地: 我有一个通用的类T
public class Node<T>
{
public Node<T> Next;
public Node<T> Previous;
T Content;
public Node<T>()
{
}
}
T可以是类似Person的泛型类,也可以是C#标准类型,如int,double ...有时需要在节点中使用另一个内容T赋值(=)内容T的值。如果有一个可以在泛型类T中实现的赋值运算符,那么t1 = t2操作将适用于泛型类和标准类型,例如int,double ......等。这将是很好的。
您有什么建议,因为C#中不允许重载赋值运算符?我正在寻找一个适用于泛型类和标准类型的优雅解决方案,这样我的代码就不必区分不同的场景。
有可能吗?非常感谢!
答案 0 :(得分:4)
您可以始终将给定类型的变量分配给该类型的另一个变量。
换句话说,写作:
public void Reassign(T source)
{
Content = source;
}
永远有效。你做必须处理许多类型的引用类型,所以分配的所有类型都是引用。如果要强制复制值,则需要添加一些泛型类型约束(ICloneable
或类似的约束可行,但是您需要使用常见.NET类型的包装器。)
换句话说,如果你这样做了:
public class Node<T> where T : ICloneable
然后你可以写
public void Assign(T source)
{
Content = source.Clone();
}
或者,如果您不需要以递归方式进行价值复制,则总是Object.MemberwiseClone
:
public void Assign(T source)
{
Content = source.MemberwiseClone();
}
另外,如果你不知道,.NET已经在LinkedList<T>
类中有一个双向链表。
答案 1 :(得分:1)
您不能重载赋值运算符,但可以创建显式或隐式类型转换运算符。这样就不必在你的情况下重载分配:
public static implicit operator Node<T>(T value) {
Node<T> node = new Node<T>();
node.Content = value;
return node;
}
这使得这项任务完全成为可能:
int value = 1;
Node<int> node = value;
如果您将implicit
替换为explicit
,则需要进行明确的类型转换:
int value = 1;
Node<int> node = (Node<T>)value;
您也可以在相反的方向创建转化:
public static implicit operator T(Node<T> node) {
return node.Content;
}
因此,您可以将节点分配给值:
Node<int> node = new Node<int>();
int value = node;
您还可以转换为不同的节点类型:
public static implicit operator Node<double>(Node<T> node) {
Node<double> destinationNode = new Node<double>();
destinationNode.Content = Convert.ToDouble(node.Content);
return destinationNode;
}
这就是你所需要的。
答案 2 :(得分:1)
由于您创建的任何模板化类或对象必须采用数据类型,因此您应始终能够将一个分配给另一个。例如,在初始化Node<T>
时,仍然需要采用数据类型:
Node<double> myNode = new Node<double>();
即使您有不同的实例,使用不同的数据类型,您也可以使用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);
等等......重载运算符太棒了;但是C#让你很容易。此外,就像布拉德利所说的那样,C#库有一个LinkedList
类,所以你不需要做所有繁重的工作。看看这里:
https://msdn.microsoft.com/en-us/library/he2s3bh7(v=vs.110).aspx
答案 3 :(得分:1)
让我提出一个略微不同的结构,允许完全自定义内容类型。
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); }
}
现在每个Student
同时是内容和列表节点。 Node<T>
类可重复使用。
现在您可以向节点类添加一些智能。例如:
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
}
}