实现一个查找表,该表获取T并返回List <T>类型的方法的属性

Bre*_*dan 7 c# lookup-tables

我有一个管理对象如集合类List<Car>List<Bike>它们属性附加伤害.

我想找到一种方法来在查找中获取每个集合的引用,这样我就可以实现诸如Add<Car>(myCar)Add(myCar)(带反射)之类的方法,并将它添加到正确的集合中.

我试过以下,

public class ListManager 
{
    private Dictionary<Type, Func<IEnumerable<object>>> _lookup 
        = new Dictionary<Type, Func<IEnumerable<object>>>();

    public ListManager()
    {
        this._lookup.Add(typeof(Car), () => { return this.Cars.Cast<object>().ToList(); });
        this._lookup.Add(typeof(Bike), () => { return this.Bikes.Cast<object>().ToList(); });
    }

    public List<Car> Cars { get; set; }
    public List<Bike> Bikes { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

但是.ToList()创建一个新列表而不是引用,因此_lookup[typeof(Car)]().Add(myCar)只会添加到字典列表中.

Jak*_*rtz 5

这将有效:

public class ListManager
{
    private Dictionary<Type, IList> _lookup
        = new Dictionary<Type, IList>();

    public ListManager()
    {
        _lookup.Add(typeof(Car), new List<Car>());
        _lookup.Add(typeof(Bike), new List<Bike>());
    }

    public List<Car> Cars
    {
        get { return (List<Car>)_lookup[typeof(Car)]; }
    }

    public List<Bike> Bikes
    {
        get { return (List<Bike>)_lookup[typeof(Bike)]; }
    }

    public void Add<T>(T obj)
    {
        if(!_lookup.ContainsKey(typeof(T))) throw new ArgumentException("obj");
        var list = _lookup[typeof(T)];

        list.Add(obj);
    }
}
Run Code Online (Sandbox Code Playgroud)

这将是如果两个很好的CarBike同一类派生或实现相同的接口.然后,您可以向Add方法添加类型约束以获取编译错误,而不是ArgumentException.

编辑

上面的简单解决方案存在一个小问题.它只有在添加到列表中的对象类型完全是存储在_lookup字典中的类型时才有效.如果您尝试添加一个对象来源于Car或者Bike将抛出.

例如,如果您定义一个类

public class Batmobile : Car { }
Run Code Online (Sandbox Code Playgroud)

然后

var listManager = new ListManager();
listManager.Add(new Batmobile());
Run Code Online (Sandbox Code Playgroud)

会扔ArgumentException.

为了避免它,您将需要一个更复杂的类型查找方法.而不是简单_lookup[typeof(Car)]应该是:

private IList FindList(Type type)
{
    // find all lists of type, any of its base types or implemented interfaces
    var candidates = _lookup.Where(kvp => kvp.Key.IsAssignableFrom(type)).ToList();

    if (candidates.Count == 1) return candidates[0].Value;

    // return the list of the lowest type in the hierarchy
    foreach (var candidate in candidates)
    {
        if (candidates.Count(kvp => candidate.Key.IsAssignableFrom(kvp.Key)) == 1)
            return candidate.Value;
    }

    return null;
}
Run Code Online (Sandbox Code Playgroud)