【问题标题】:Using IComparer<T>.Compare(T,T) in C#在 C# 中使用 IComparer<T>.Compare(T,T)
【发布时间】:2014-12-22 15:53:10
【问题描述】:

我一直在尝试创建一个通用的反向优先级队列,但在 EnQueue 中,但我仍然无法管理使用 IComparer 带来的错误。

错误:错误 1 ​​非静态字段、方法或属性“System.Collections.Generic.IComparer.Compare(T, T)”需要对象引用

public void inQ(T dat)//adding element in place, increasing order
    {
        if (start == null)//that means that the RPQ is empty
        {
            start = new node(dat);
            return;
        }
        if (IComparer<T>.Compare(start.data, dat) > 0)//Doesn't work
        {
            start = new node(dat, start);
            return;
        }
        //Default Case
        //no need for an else, actually
        node q = start;
        while (q.next != null && Comparer<T>.Default.Compare(q.next.data, dat) < 0)//Works Perfectly
            q++;
        q.next = new node(dat, q.next);
    }

【问题讨论】:

    标签: c# icomparer


    【解决方案1】:

    发生了什么

    您需要一个IComparer&lt;T&gt; 的实例才能在其上调用Compare 方法...记住这是一个接口,它没有静态方法。

    这就是为什么这不起作用:

    IComparer<T>.Compare(start.data, dat) > 0
    

    另一方面,Comparer&lt;T&gt; 是一个类,它为您提供了一个静态属性 Default,它为您提供了一个 IComparer&lt;T&gt; 的实例...

    这就是它起作用的原因:

    Comparer<T>.Default.Compare(q.next.data, dat) < 0
    

    获取IComparer&lt;T&gt; 的实例

    您可以考虑使用 IComparer&lt;T&gt; 的实例存储一个字段,然后改用它。这将最大限度地减少混淆,并允许您在构造函数中获得一个 IComparer&lt;T&gt; 以存储在该字段中 - 这在客户想要自定义行为的情况下很有用。


    默认实例

    如果你想使用默认的比较器,你可以从中获取:

    var comparer = Comparer<T>.Default;
    

    此比较器将为您使用的任何T 提供默认行为。此行为等效于在 T 的实例上调用 CompareTo,并对空值进行额外处理。由于当您的实例为 null 时无法使用方法 CompareTo,您可能需要在调用 CompareTo 之前检查 null ...使用比较器消除了问题。


    实现IComparer&lt;T&gt;

    由于IComparer&lt;T&gt; 是一个接口,您可以编写一个类来实现它,该类必须有一个Compare 方法,具有您想要的任何逻辑。然后创建该类的一个实例,并在系统需要IComparer&lt;T&gt; 的地方使用它。

    See the an example of implementing IComparer&lt;T&gt; on MSDN

    // This class is not demonstrated in the Main method 
    // and is provided only to show how to implement 
    // the interface. It is recommended to derive 
    // from Comparer<T> instead of implementing IComparer<T>. 
    public class BoxComp : IComparer<Box>
    {
        // Compares by Height, Length, and Width. 
        public int Compare(Box x, Box y)
        {
            if (x.Height.CompareTo(y.Height) != 0)
            {
                return x.Height.CompareTo(y.Height);
            }
            else if (x.Length.CompareTo(y.Length) != 0)
            {
                return x.Length.CompareTo(y.Length);
            }
            else if (x.Width.CompareTo(y.Width) != 0)
            {
                return x.Width.CompareTo(y.Width);
            }
            else
            {
                return 0;
            }
        }
    }
    

    您的比较器将是该类的一个实例:

    var comparer = new BoxComp();
    

    注意:文档实际上建议从Comparer&lt;T&gt;继承而不是直接实现IComparer&lt;T&gt;,实用的原因是Comparer&lt;T&gt;除了IComparer&lt;T&gt;之外还实现了IComparer


    使用委托创建 IComparer&lt;T&gt;

    如果您不熟悉委托是什么,假设它是对方法的引用,因此您可以拥有一个对方法的引用并传递它的变量。

    你可以创建一个IComparer&lt;T&gt;,如果你有一个委托给一个进行比较的方法......这是通过调用方法Comparer&lt;T&gt;.Create来完成的,女巫将一个委托给你想要的方法。例如,您可以按如下方式使用 lambda 表达式:

    var comparer = Comparer<string>.Create
    (
        (str1, str2) => str1.Length.CompareTo(str2.Length)
    );
    

    上面的代码是这个的简写:

    Comparison<string> comparison = (str1, str2) => str1.Length.CompareTo(str2.Length);
    var comparer = Comparer<string>.Create(comparison);
    

    这又是这个的简写:

    Comparison<string> comparison = delegate(string str1, string str2)
    {
       return str1.Length.CompareTo(str2.Length);
    };
    var comparer = Comparer<string>.Create(comparison);
    

    对于这样的事情,什么是糖(除了在上面的代码中该方法是匿名的):

    Comparison<string> comparison = StringComparison;
    var comparer = Comparer<string>.Create(comparison);
    
    // ...
    
    private static int StringComparison(string str1, string str2)
    {
        return str1.Length.CompareTo(str2.Length);
    }
    

    额外读数

    【讨论】:

    • Comparer 是否适用于我制作的任何自定义 Compare 方法?
    • 由于IComparer&lt;T&gt; 是一个接口,您可以编写一个类来实现它,该类必须有一个Compare 方法以及您想要的任何逻辑。然后创建该类的实例并在系统需要IComparer&lt;T&gt; 的地方使用它。 See the an example of implementing IComparer&lt;T&gt; on MSDN
    • @Sherbi7y Comparer&lt;T&gt;.Default 不会使用您创建的自定义 IComparer&lt;T&gt;Comparer&lt;T&gt; 没有发现自定义实现。如果要使用自定义比较器,则需要获取它的实例并使用它[参见答案如何获取一个]。这是一种常见的做法——如果你的类需要它——让构造函数重载接受IComparer&lt;T&gt;,如果没有提供则回退到Comparer&lt;T&gt;.Default。像这样_comparer = comparer ?? Comparer&lt;T&gt;.Default;.
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-27
    相关资源
    最近更新 更多