想象一下我有这样的课:

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进行搜索,因为我们知道TMyKey,并且列表是使用MyKeyKey进行排序的:

public int Search(MyKey searchKey)
{
    return list.BinarySearch(searchKey); // Does not compile!
}


但是,由于BinarySearch采用TT可以是任何自定义类),因此无法编译。

如果我提供比较器,它也不起作用。想象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/

10-12 21:15