我有一个包含许多不同类型的泛型集合的类。
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类中的集合类型是从基类调用的。解决方案应该是通用的。我想使用反射可能是一种可能的方法吗?
答案 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; }
}