获取基于泛型

时间:2015-11-18 17:19:39

标签: c# generics collections

我有一个包含许多不同类型的泛型集合的类。

public class InMemoryDatabase
{
    public HashSet<Car> Cars { get; set; }
    public HashSet<Truck> Trucks { get; set; }
    public HashSet<Bike> Bikes { get; set; }
}

如何根据泛型类型检索集合?

E.g。

public HashSet<TEntity> GetCollection<TEntity>()
{
   //how to retrieve collection from InMemoryDatabase class?
}

可以按如下方式调用:

HashSet<Bike> = GetCollection<Bike>();

更新

请注意,GetCollection方法的实现应该事先不知道InMemoryDatabase类中的集合类型是从基类调用的。解决方案应该是通用的。我想使用反射可能是一种可能的方法吗?

4 个答案:

答案 0 :(得分:2)

听起来你想要每种类型一个HashSet:

  public class InMemoryDatabase
  {
      private Dictionary<Type, IEnumerable> _hashSets = new Dictionary<Type, IEnumerable>();

      // Returns or creates a new HashSet for this type.
      public HashSet<T> GetCollection<T>()
      {
          Type t = typeof(T);

          if (!_hashSets.ContainsKey(t))
          {
              _hashSets[t] = new HashSet<T>();
          }

          return (_hashSets[t] as HashSet<T>);
       }
    }

答案 1 :(得分:1)

有多种方法可以做到这一点。一种方法是简单地测试类型并返回适当的字段:

public HashSet<TEntity> GetCollection<TEntity>() 
{
    var type = typeof(TEntity);

    if(type == typeof(Bike))
       return (HashSet<TEntity>)(object)Bikes;
    if(type == typeof(Car))
       return (HashSet<TEntity>)(object)Cars;
    if(type == typeof(Truck))
       return (HashSet<TEntity>)(object)Trucks;

    throw new InvalidOperationException();
}   

需要转发到object的中间人,因为在这种情况下编译器不知道TEntity实际上是其中一种类型,因此我们使用类型擦除来确保转换有效。它应该在JIT步骤中进行优化,因为该方法是针对该特定类型构建的。

答案 2 :(得分:1)

我看到的最好的方法是反映一次类,并构建一个“集合选择器映射”,供这样的泛型函数使用

public class InMemoryDatabase
{
    static readonly Dictionary<Type, Func<InMemoryDatabase, object>> collectionMap;
    static InMemoryDatabase()
    {
        collectionMap =
            (from p in typeof(InMemoryDatabase).GetProperties()
             where p.CanRead &&
                p.PropertyType.IsGenericType && 
                p.PropertyType.GetGenericTypeDefinition() == typeof(HashSet<>)
             select new
             {
                 Type = p.PropertyType.GetGenericArguments()[0],
                 Selector = (Func<InMemoryDatabase, object>)Delegate.CreateDelegate(
                     typeof(Func<InMemoryDatabase, object>), p.GetMethod)
             }).ToDictionary(e => e.Type, e => e.Selector);
    }
    public HashSet<TEntity> GetCollection<TEntity>()
    {
        return (HashSet<TEntity>)collectionMap[typeof(TEntity)](this);
    }
    // Collections
    public HashSet<Car> Cars { get; set; }
    public HashSet<Truck> Trucks { get; set; }
    public HashSet<Bike> Bikes { get; set; }
    // ...
}

答案 3 :(得分:1)

这可能看起来有点粗糙,但即使你没有为TEntity提供有效的类型它也能正常工作......

public class InMemoryDatabase
{
    public HashSet<TEntity> GetCollection<TEntity>()
    {
        var a = this.GetType().GetProperties();
        HashSet<TEntity> retVal = null;
        foreach (var name in a.Select(propertyInfo => propertyInfo.Name))
        {
            retVal = this.GetType().GetProperty(name).GetValue(this, null) as HashSet<TEntity>;
            if (retVal != null)
            {
                break;
            }
        }

        return retVal;
    }
    public HashSet<Car> Cars { get; set; }
    public HashSet<Truck> Trucks { get; set; }
    public HashSet<Bike> Bikes { get; set; }    
}