哪个用?在这种情况下,IComparable泛型或非泛型

时间:2011-05-30 12:28:19

标签: .net generics collections

我有一个通用的BST和一个dataItem类来充当treeNode的值。

public class BinarySearchTree<T> : ICollection<T>  where T : IComparable
{

}

public class EnglishDictionaryWord
    : IComparer<EnglishDictionaryWord>, IComparable<EnglishDictionaryWord>
{
    public EnglishDictionaryWord(string word, WordCompareType type)
    {
        Word = word;
        Length = Word.Length;
        _compareType = type;
    }

    public int Compare(EnglishDictionaryWord x, EnglishDictionaryWord y)
    {
        if (_compareType == WordCompareType.Length)
            return new WordLengthComparer().Compare(x, y);
        else if (_compareType == WordCompareType.Lexical)
            return new WordLexicalComparer().Compare(x, y);
        else
            throw new InvalidOperationException("Unsupported Comparison type");
    }

    public int CompareTo(EnglishDictionaryWord obj)
    {
        return Compare(this, obj);
    }
} 

public class WordLengthComparer : IComparer<EnglishDictionaryWord>
{
    public WordLengthComparer()
    {

    }
    public int Compare(EnglishDictionaryWord x, EnglishDictionaryWord y)
    {
        return x.Length - y.Length;
    }
}

and similar Lexical comparer class.

现在我尝试使用:

BinarySearchTree<EnglishDictionaryWord> _tree = 
    new BinarySearchTree<EnglishDictionaryWord>();

我收到编译错误:

类型'DsLib.EnglishDictionaryWord'不能在泛型类型或方法'DsLib.BinarySearchTree'中用作类型参数'T'。没有从'DsLib.EnglishDictionaryWord'到'System.IComparable'的隐式引用转换。

如果我尝试制作

public class BinarySearchTree<T> : ICollection<T>  where T : IComparable<T>

然后我得到关于拳击转换不可用的编译错误。

类型'T'不能用作泛型类型或方法'DsLib.BinaryTreeNode'中的类型参数'T'。从'T'到'System.IComparable'没有装箱转换或类型参数转换。

我有两个问题:

(1)。 我对泛型实现感到困惑。有人可以详细说明如何纠正它吗?和一般模式,以避免将来出现此类错误。 何时使用IComparable<T>和何时IComparable

(2)。这个比较器模式是否正确,在dataitem类中有比较器?因为用户将提供要插入树中的新EnglishWord。他可能会为每个单词使用不同的比较器。然后它会破坏树。

编辑:添加了BSTNode类代码

public class BinaryTreeNode<T> where T : IComparable
{
    public BinaryTreeNode(T value)
    {
        Value = value;
    }

    public T Value { get; protected internal set; }
    public BinaryTreeNode<T> Right { get; protected internal set; }
    public BinaryTreeNode<T> Left { get; protected internal set; }
    public BinaryTreeNode<T> Parent { get; protected internal set; }

    public int Height { get; protected internal set; }
}

3 个答案:

答案 0 :(得分:1)

您还需要更改BinaryTreeNode

public class BinaryTreeNode<T> where T : IComparable<T>

答案 1 :(得分:1)

我尝试使用以下定义代码:

  public class BinarySearchTree<T>
      : ICollection<T>
      where T : IComparable<T>

  public class EnglishDictionaryWord
      : IComparer<EnglishDictionaryWord>,
        IComparable<EnglishDictionaryWord>

  public class WordLengthComparer
      : IComparer<EnglishDictionaryWord>

它工作正常 - 它编译,执行等...(.NET 4.0,c#):

 BinarySearchTree<EnglishDictionaryWord> _tree = 
     new BinarySearchTree<EnglishDictionaryWord>();

并回答你的其他问题:

  1. 您应该始终支持IComparable<T>而不是IComparable。它更快,更不容易出错(没有铸造/装箱/拆箱)等等......至于你的问题:为什么需要它?它很简单 - IComparable<T>和{{1}是不同的类型(它们有相似的名称,但不要让你感到困惑 - 类型 不同)。因此,您只需要在引用的地方放置相同的类型。
  2. 插入树中的数据应具有比较逻辑。定义树时,您可以准确指定它将使用哪些类型的项目 - 因此,只要该对象存在,就不能在其中添加一些完全不同的类型。例如,如果你定义:

    IComparable

  3. 您无法添加BinarySearchTree<EnglishDictionaryWord> _tree;其他内容,例如_tree,因此树确实正确保留了其结构,因为只添加了SpanglishDictionaryWord项,并且它们已定义结构并进行比较逻辑是一致的。

    编辑我刚看到你有一个“Has”比较器逻辑,而不是纯粹的“Is”可比较。应该修复(从数据项中删除对比较器的引用) - 如果没有,你是对的 - 树可能会被破坏......

    EDIT2 如果您需要数据项具有灵活的比较逻辑(即改变它们的比较方式,这很奇怪,所以考虑一下),那么BST必须有一个参考您打算与它一起使用的比较器的实例:要么将包装比较器的项目和实际项目放在一起,要么将项目的Comparer作为BST的属性,并在决定要转到哪个分支时在每个数据项上使用它

答案 2 :(得分:1)

  

如果我在Tree相关的类/方法中更改为IComparable<T>,则编译它。为什么需要这个?

IComparable<T>不会继承IComparable

  

和第二个问题?

你说得对 - 如果不同的项目有不同的排序类型,列表就会出现故障。更好的模式是让类型拥有单个默认排序行为,然后允许集合接受并使用备用IComparers。要查看此操作,请检查Enumerable.OrderBy

的重载