用逆变类型搜索泛型c#列表
本文关键字:泛型 列表 搜索 类型 | 更新日期: 2023-09-27 18:10:11
假设我有一个这样的类:
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);
}
}
Linq就是你要找的!
首先,确保您在使用中引用了System.Linq
。
然后可以使用以下代码获取所有匹配的列表项:
IEnumerable<MyNamedKey> found = list.Where(l => l.Key == 2);
获取单个项目,使用:
MyNamedKey found = list.FirstOrDefault(l => l.Key == 2);