【问题标题】:Which to use ? IComparable generic or non-generic in this scenario使用哪个?在这种情况下 IComparable 泛型或非泛型
【发布时间】:2011-05-30 12:28:19
【问题描述】:

我有一个通用的 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&lt;T&gt;,何时使用IComparable

(2)。这个比较器模式是否正确,在数据项类中有比较器?因为用户将提供新的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; }
}

【问题讨论】:

  • 我在任何地方都没有看到DsLib.BinaryTreeNode...
  • @Kamarey 我的问题是关于 IComparable 和 IComparable 而不是 IComparer 和 IComparable

标签: .net generics collections


【解决方案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&lt;T&gt; 而不是IComparable。它更快,更不容易出错(没有铸造/装箱/拆箱)等...至于你的问题:为什么需要它?这很简单 - IComparable&lt;T&gt;IComparable 是不同的类型(它们有相似的名称,但不要让您感到困惑 - 类型 不同)。因此,您只需要将相同的类型放在任何引用的位置。

  2. 插入到树中的数据应该有比较逻辑。当您定义树时,您可以准确指定它将使用哪些类型的项目 - 因此只要该对象存在,您就不能向其中添加一些完全不同的类型。例如,如果您定义:

    BinarySearchTree&lt;EnglishDictionaryWord&gt; _tree;

您不能向_tree 添加其他内容,例如SpanglishDictionaryWord,因此树确实保持其结构正确,因为仅添加了EnglishDictionaryWord 的项目,并且它们定义了结构和比较一致的逻辑。

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

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

【讨论】:

  • @Daniel 是的,如果我在 Tree 相关的类/方法中随处更改为 IComparable,它会编译。没关系。你能回答为什么这是必需的和第二个问题吗?主要是我希望了解原因,而不是在未来进行反复试验:)
  • +1 表示“有”..“是”。请参阅我对@David B 答案的评论。并增加你在那部分的答案。谢谢。
【解决方案2】:

您也需要更改BinaryTreeNode

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

【讨论】:

  • 我也这样做了。同样的错误。还有一个问题是为什么?需要对所提出的问题进行一些解释。
【解决方案3】:

如果我在 Tree 相关的类/方法中的任何地方更改为 IComparable&lt;T&gt;,它就会编译。为什么需要这样做?

IComparable&lt;T&gt; 不继承自 IComparable

第二个问题?

你是对的 - 如果不同的项目有不同的排序类型,列表将出现故障。更好的模式是让类型拥有一个默认排序行为,然后允许集合接受和使用备用 IComparers。要查看实际情况,请检查 Enumerable.OrderBy 的重载

【讨论】:

  • 所以你的意思是,TreeOfEnglishWords.OrderBy(new WordLengthComparer()) 类似的东西?我的树在添加/包含操作期间也需要比较器。那么树应该在其构造函数中接受默认比较器吗?
  • 是的,构造函数。类似于通用字典如何在其构造函数中接受 IEqualityComparermsdn.microsoft.com/en-us/library/6918612z.aspx
猜你喜欢
  • 2013-07-22
  • 2019-01-02
  • 2014-04-13
  • 1970-01-01
  • 2020-02-27
  • 1970-01-01
  • 1970-01-01
  • 2021-03-07
  • 1970-01-01
相关资源
最近更新 更多