想象一下我有这样的课:
class MyKey : IComparable<MyKey> {
public int Key { get; private set; }
public MyKey(int key) { Key = key; }
public int CompareTo(MyKey that) {
return that.Key - this.Key;
}
}
此外,我有一个像这样的通用包装器类:
class MyListWrapper<T> where T : MyKey
{
private List<T> list;
public MyListWrapper(IEnumerable<T> items)
{
list = new List<T>(items);
list.Sort();
}
public int Search(T searchKey)
{
return list.BinarySearch(searchKey);
}
}
这使人们可以存储从
MyKey
继承的自定义类,并且效果很好。但是,也可以使用MyKey
进行搜索,因为我们知道T
是MyKey
,并且列表是使用MyKey
的Key
进行排序的:public int Search(MyKey searchKey)
{
return list.BinarySearch(searchKey); // Does not compile!
}
但是,由于
BinarySearch
采用T
(T
可以是任何自定义类),因此无法编译。如果我提供比较器,它也不起作用。想象
MyKey
不可比,但是我做了一个使用Key
的自定义比较器。我可以在排序和搜索时使用它。是否可以使用
MyKey
搜索列表?我不喜欢将列表存储为List<MyKey>
并在使用它们时强制转换值(这违反了通用列表的目的)。我也无法将类型List<T>
的列表转换为List<MyKey>
。 最佳答案
您可以创建一个从MyNamedKey
继承的包装器类,也可以创建MyNamedKey
本身的新实例来仅搜索项目。
var mySearchKey = new MyKey { Key = 2 };
var index = list.BinarySearch(new MyNamedKeyWrapper(mySearchKey));
class MyNamedKeyWrapper : MyNamedKey
{
public MyNamedKeyWrapper(MyKey key)
{
this.Key = key.Key;
}
}
这将帮助您维持O(log n),同时增加少量分配成本。
或者,如果您更喜欢使用脆性反射,则可以..获取基础数组的实例并将其强制转换为
MyKey[]
(这是有效的,因为数组是协变的),然后使用Array.BinarySearch
。var array = (MyKey[])list.GetType()
.GetField("_items", BindingFlags.Instance | BindingFlags.NonPublic)
.GetValue(list);
var index = Array.BinarySearch(array, mySearchKey);
编辑:由于您不知道最派生的类型,如果您用通用参数约束
new()
,则可以实现所需的功能class MyListWrapper<T> where T : MyKey, new()
{
private readonly List<T> list;
public MyListWrapper(IEnumerable<T> items)
{
list = new List<T>(items);
list.Sort();
}
public int Search(MyKey searchKey)
{
T dummyKey = new T() { Key = searchKey.Key };
return list.BinarySearch(dummyKey);
}
}
关于c# - 搜索具有相反类型的通用C#列表,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/32241056/