在 C# 中比较 "Object" 类型的对象
Comparing object of type "Object" in C#
我正在尝试在 C#
中实现树数据结构,我已经在 C++
中实现了 100 次
但是在这里,当我试图保持 Tree 的通用性以接受任何数据类型时,我让每个 Node
都在一个 Object
类型的对象中拥有它的数据,如下所示:
public class Node
{
public object Data;
public Node Right;
public Node Left;
public Node(object value)
{
NodeContent = value;
Right = Left = null;
}
}
但是当我尝试实现 insert
时,我需要比较两个 Object
类型的对象,以便知道是在左侧还是右侧插入一个新节点当前节点。当我尝试检查这个
if(value < childPtr.Data)
其中 value
是要插入的值,我收到一条错误消息,提示我无法比较两个 Object
类型的对象。那么有没有办法解决这个问题?
由于您需要比较数据,更好的方法是:
public class Node
{
public IComparable Data;
public Node Right;
public Node Left;
public Node(IComparable value)
{
Data = value;
Right = Left = null;
}
}
以后你可以做:
if(value.CompareTo(childPtr.Data) < 0)
您的方法的问题在于 Data
可以是任何类型。您的设计允许您将多种类型放入同一棵树中。因此,一个节点可能有一个 string
,另一个可能有一个 double
,第三个可能有一个对 user-defined 类型的引用。如果让 Node
构造函数采用 IComparable
实例,则假设树中的所有项都属于同一类型,或者它们的 IComparable
接口实现知道如何比较所有可能数据类型的值。
简而言之,虽然您所做的会起作用,但它根本不是类型安全的。
您所拥有的是非常 C-like 要做的事情。在 C++ 中,您会使用模板来避免这种可憎的事情。在 C# 中,您使用泛型。
我赞同评论中的建议:如果你想要一个通用数据结构,制作一个通用数据结构。使用 built-in 集合,例如,如果您想要一个整数列表,您可以编写:
var list_of_integers = new List<int>();
如果你想要一个字符串列表:
var list_of_strings = new List<string>();
如果你想创建一个通用的树集合,你将从:
开始
public class MyGenericTree<T>
{
public class Node
{
public T Data;
public Node Left;
public Node Right;
public Node(T data)
{
Data = data;
}
}
private readonly IComparer<T> _comparer;
public MyGenericTree(IComparer<T> comparer = null)
{
_comparer = comparer ?? Comparer<T>.Default;
}
}
然后你创建它:
var myTree = new MyGenericTree<string>(); // or int, or whatever type
如果要自定义比较函数,你写:
// Create a tree that stores case-insensitive strings
var myTree = new MyGenericTree<string>(StringComparer.CurrentCultureIgnoreCase);
这会强制 Data
始终为兼容类型。您要么使用该类型的默认比较器,要么使用传递给构造函数的比较器接口。
并且在进行比较时,它是:
int a = _comparer.Compare(node1, node2);
if (a < 0)
// node1 < node2
else if (a > 0)
// node1 > node2
else
// node1 == node2
如果你真的想在树中存储未类型化的 object
引用,你可以轻松地写:
var myTree = new MyGenericTree<object>(some_object_comparer);
虽然你为什么想要做这样的事情有点神秘。
我知道泛型一开始看起来有点奇怪,但在使用它们一天左右后,您就会明白它们非常灵活并且类型安全。
我正在尝试在 C#
中实现树数据结构,我已经在 C++
中实现了 100 次
但是在这里,当我试图保持 Tree 的通用性以接受任何数据类型时,我让每个 Node
都在一个 Object
类型的对象中拥有它的数据,如下所示:
public class Node
{
public object Data;
public Node Right;
public Node Left;
public Node(object value)
{
NodeContent = value;
Right = Left = null;
}
}
但是当我尝试实现 insert
时,我需要比较两个 Object
类型的对象,以便知道是在左侧还是右侧插入一个新节点当前节点。当我尝试检查这个
if(value < childPtr.Data)
其中 value
是要插入的值,我收到一条错误消息,提示我无法比较两个 Object
类型的对象。那么有没有办法解决这个问题?
由于您需要比较数据,更好的方法是:
public class Node
{
public IComparable Data;
public Node Right;
public Node Left;
public Node(IComparable value)
{
Data = value;
Right = Left = null;
}
}
以后你可以做:
if(value.CompareTo(childPtr.Data) < 0)
您的方法的问题在于 Data
可以是任何类型。您的设计允许您将多种类型放入同一棵树中。因此,一个节点可能有一个 string
,另一个可能有一个 double
,第三个可能有一个对 user-defined 类型的引用。如果让 Node
构造函数采用 IComparable
实例,则假设树中的所有项都属于同一类型,或者它们的 IComparable
接口实现知道如何比较所有可能数据类型的值。
简而言之,虽然您所做的会起作用,但它根本不是类型安全的。
您所拥有的是非常 C-like 要做的事情。在 C++ 中,您会使用模板来避免这种可憎的事情。在 C# 中,您使用泛型。
我赞同评论中的建议:如果你想要一个通用数据结构,制作一个通用数据结构。使用 built-in 集合,例如,如果您想要一个整数列表,您可以编写:
var list_of_integers = new List<int>();
如果你想要一个字符串列表:
var list_of_strings = new List<string>();
如果你想创建一个通用的树集合,你将从:
开始public class MyGenericTree<T>
{
public class Node
{
public T Data;
public Node Left;
public Node Right;
public Node(T data)
{
Data = data;
}
}
private readonly IComparer<T> _comparer;
public MyGenericTree(IComparer<T> comparer = null)
{
_comparer = comparer ?? Comparer<T>.Default;
}
}
然后你创建它:
var myTree = new MyGenericTree<string>(); // or int, or whatever type
如果要自定义比较函数,你写:
// Create a tree that stores case-insensitive strings
var myTree = new MyGenericTree<string>(StringComparer.CurrentCultureIgnoreCase);
这会强制 Data
始终为兼容类型。您要么使用该类型的默认比较器,要么使用传递给构造函数的比较器接口。
并且在进行比较时,它是:
int a = _comparer.Compare(node1, node2);
if (a < 0)
// node1 < node2
else if (a > 0)
// node1 > node2
else
// node1 == node2
如果你真的想在树中存储未类型化的 object
引用,你可以轻松地写:
var myTree = new MyGenericTree<object>(some_object_comparer);
虽然你为什么想要做这样的事情有点神秘。
我知道泛型一开始看起来有点奇怪,但在使用它们一天左右后,您就会明白它们非常灵活并且类型安全。