具有Text属性的所有对象的Generic Comparer

时间:2015-09-08 11:57:49

标签: c# generics interface icomparer

我正在尝试为具有Text属性的所有对象实现通用比较器(用于排序)...因此可以比较两个ASP.net文本框,两个标签或在此特定情况下两个RadTreeNodes在telerik RadTreeView中(只要它们具有Text属性)。所以我把以下内容放在一起尝试,但这样做会产生如下错误:

我有以下代码:

public class TextComparer<T> : IComparer
    where T : IHasTextProperty
    {
        public int Compare(object a, object b)
        {
            T nodeA = (T)a;
            T nodeB = (T)b;
            return nodeA.Text.CompareTo(nodeB.Text);
        }
    } 

    public interface IHasTextProperty
    {
        string Text { get; set; }
    }

然后计划像这样使用它......

Array.Sort(nodes, new TextComparer<RadTreeNode>());

但请收到以下消息:

  

错误6613“Telerik.Web.UI.RadTreeNode”类型不能用作   在泛型类型或方法'TextComparer'中输入参数'T'。   没有隐式引用转换   'Telerik.Web.UI.RadTreeNode'到'IHasTextProperty'

我确信这是一个简单的解决方法,但我对如何修复它感到有点困惑。

2 个答案:

答案 0 :(得分:3)

您正在尝试在C#中执行duck-typing,这不支持鸭子输入。在某些语言中,您可以根据具有特定属性的类型进行匹配,例如Text。这仅适用于语言支持此技术的情况。

使用C#,类必须明确地实现一个接口,以使其被认为具有该接口的类型。 Telerik.Web.UI.RadTreeNode未实施IHasTextPropertyT与实施IHasTextProperty的类型有关,因此您会收到错误。

在这种情况下,你真的不能使用泛型。您需要测试ab是否具有Text属性。这可以使用反射或使用dynamic来完成。不幸的是,这两种解决方案都不会像你试图做的那样整洁。

答案 1 :(得分:1)

System.Web.UI提供了自己的IHasTextPropertyITextControlmsdn),其行为与IHasTextProperty完全相同。缺点是您不能确定RadTreeNode(或任何其他第三方控件)实现此接口。

唯一可以确定的方法是从编译时删除此检查并通过反射将其置于运行时,这很简单,但可能不是您想要的。如果您仍想在ArgumentException的构造函数中使用TextComparer,请在此处使用它,以确保仅比较有效对象。

public class TextComparer<T> : IComparer
{
    private bool HasTextProperty(Type t)
    {
        return (t.GetProperty("Text", typeof(string)) != null);
    }

    private string GetTextPropertyValue(object obj)
    {
        return obj.GetType().GetProperty("Text", typeof(string)).GetValue(obj) as string;
    }

    public TextComparer()
    {
        if (!HasTextProperty(typeof(T))) throw new ArgumentException(string.Format("{0} doesn't provide a Text property", typeof(T).Name), "T");
    }

    public int Compare(object x, object y)
    {
        return GetTextPropertyValue(x).CompareTo(GetTextPropertyValue(y));
    }
}