泛型比较器用于所有具有Text属性的对象

本文关键字:属性 对象 Text 用于 泛型 比较器 | 更新日期: 2023-09-27 18:11:45

我正试图实现一个通用比较器(用于排序)为所有对象有一个文本属性…所以两个ASP.net文本框可以比较,两个标签,或者在这个特定的情况下,两个radtreenode在一个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' to 'IHasTextProperty'

我相信这是一个简单的修复,但我只是有点难住如何修复它。

泛型比较器用于所有具有Text属性的对象

您试图在c#中执行duck-typing,而c#不支持duck-typing。在某些语言中,您可以根据具有特定属性的类型来匹配类型,例如本例中的Text。这只有在语言支持此技术时才有效。

在c#中,一个类必须显式地实现一个接口,才能被认为具有该接口的类型。Telerik.Web.UI.RadTreeNode不实现IHasTextPropertyT被包含到实现IHasTextProperty的类型中,因此您得到了您所看到的错误。

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

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

唯一确定的方法是从编译时删除此检查,并通过反射将其放入运行时,这非常简单,但可能不是您想要的。如果你仍然想使用它,这里有一个在TextComparer的构造函数中使用ArgumentException的例子,以确保只比较有效的对象。

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));
    }
}
相关文章: