泛型比较器用于所有具有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'
我相信这是一个简单的修复,但我只是有点难住如何修复它。
您试图在c#中执行duck-typing,而c#不支持duck-typing。在某些语言中,您可以根据具有特定属性的类型来匹配类型,例如本例中的Text
。这只有在语言支持此技术时才有效。
在c#中,一个类必须显式地实现一个接口,才能被认为具有该接口的类型。Telerik.Web.UI.RadTreeNode
不实现IHasTextProperty
。T
被包含到实现IHasTextProperty
的类型中,因此您得到了您所看到的错误。
在这种情况下你真的不能使用泛型。您需要测试a
和b
是否具有Text
属性。这可以通过反射或dynamic
来实现。这两种解决方案都不会像您试图做的那样简洁。
System.Web.UI
提供了自己的IHasTextProperty
即ITextControl
(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));
}
}