我有一个泛型类GenericClass<T>
,我想要汇集实例
我很想知道我是否可以获得语法:
MyGenericPool = new GenericPool<GenericClass>();
// Or maybe it's MyGenericPool = new GenericPool<GenericClass<>>();
GenericClass<TGenericParam> GenericClassInstance =
MyGenericPool.Get<TGenericParam>();
(我对泛型的理解说,不,我不能,不要愚蠢的语法不存在/不会起作用,但我对其他人的想法很感兴趣。)
我有点怀疑,因为根据我的理解,GenericClass<string>
和GenericClass<int>
类型与类型系统的观点并不真正相关。
现在,我意识到我可以接近,即:
GenericClass<TGenericParam> GenericClassInstance =
GenericPool.Get<GenericClass<TGenericParam>>();
然后让GenericPool
只在某个地方存储Dictionary<Type, ObjectPool<object>>
我很想知道我是否可以避免这样做。我不想每次都要指定泛型类型,作为调用者,我只更改泛型类型参数。我也希望能够强制执行(编译时)所有进入我的GenericObjectPool<T>
的对象属于集合泛型类型(T<>
)。
我认为问题源于无法将泛型类型参数视为通用类型参数。如果我能做到(我可以吗?)那么下面的内容可能会起作用:
public class GenericClassPool<TGeneric> where TGeneric : class<>
{
private readonly Dictionary<Type, object> objectPools = new Dictionary<Type, object>();
private void EnsureObjectPoolExists<TGenericParam>()
{
if (!objectPools.ContainsKey(typeof(TGenericParam)))
{
objectPools.Add(typeof(TGenericParam), new ObjectPool<TGeneric<TGenericParam>>(() => Activator.CreateInstance(typeof(TGeneric<TGenericParam>)) as TGeneric<TGenericParam>));
}
}
private ObjectPool<TGeneric<TGenericParam>> GetPool<TGenericParam>()
{
EnsureObjectPoolExists<TGenericParam>();
return (objectPools[typeof(TGenericParam)] as ObjectPool<TGeneric<TGenericParam>>);
}
public void Add<TTypeParam>(TGeneric<TGenericParam> obj)
{
EnsureObjectPoolExists<TTypeParam>();
GetPool<TGenericParam>().Add(obj);
}
public TGeneric<TGenericParam> Get<TGenericParam>()
{
return GetPool<TGenericParam>().Get() as TGeneric<TGenericParam>;
}
}
我可以获得我想要的语法(在顶部)吗?如果没有,我能接近多少?
答案 0 :(得分:4)
您尝试实现的解决方案/语法不起作用,因为如果没有类型参数作为另一个泛型类型的类型参数,则不能使用泛型类型。
但是,您可以通过以下方法获得类似的结果:
类似的东西:
public class ObjectPool
{
Dictionary<Type, object> _objectPool = new Dictionary<Type, object>();
public void Add<TKey, TValue>(TValue value)
{
_objectPool.Add(typeof(TKey), value);
}
public TValue Get<TKey, TValue>() where TValue : class
{
object value;
if(_objectPool.TryGetValue(typeof(TKey), out value))
return value as TValue;
return null;
}
}
public class GenericClassPool : ObjectPool
{
public void Add<TGenericParam>(GenericClass<TGenericParam> obj)
{
Add<TGenericParam, GenericClass<TGenericParam>>(obj);
}
public GenericClass<TGenericParam> Get<TGenericParam>()
{
return Get<TGenericParam, GenericClass<TGenericParam>>();
}
}
用法如下:
var pool = new GenericClassPool();
pool.Add(new GenericClass<string> { Property = "String" });
pool.Add(new GenericClass<int> { Property = 0 });
GenericClass<string> firstObject = pool.Get<string>();
GenericClass<int> secondObject = pool.Get<int>();
此解决方案的缺点是您需要为要池的每个泛型类型创建一个池类,因此您可能会从<className>Pool
派生出很多ObjectPool
个类。
为了使其可用,所有实际代码都需要在ObjectPool
类中,并且只有提供泛型参数的代码仍保留在派生类中。
答案 1 :(得分:0)
我想分享自己的游泳池课程。它们与发布的其他代码具有类似的API,但在我的完全偏见的意见中更加开发和灵活。
单一类型对象池:
/// <summary>
/// Allows code to operate on a Pool<T> without casting to an explicit generic type.
/// </summary>
public interface IPool
{
Type ItemType { get; }
void Return(object item);
}
/// <summary>
/// A pool of items of the same type.
///
/// Items are taken and then later returned to the pool (generally for reference types) to avoid allocations and
/// the resulting garbage generation.
///
/// Any pool must have a way to 'reset' returned items to a canonical state.
/// This class delegates that work to the allocator (literally, with a delegate) who probably knows more about the type being pooled.
/// </summary>
public class Pool<T> : IPool
{
public delegate T Create();
public readonly Create HandleCreate;
public delegate void Reset(ref T item);
public readonly Reset HandleReset;
private readonly List<T> _in;
#if !SHIPPING
private readonly List<T> _out;
#endif
public Type ItemType
{
get
{
return typeof (T);
}
}
public Pool(int initialCapacity, Create createMethod, Reset resetMethod)
{
HandleCreate = createMethod;
HandleReset = resetMethod;
_in = new List<T>(initialCapacity);
for (var i = 0; i < initialCapacity; i++)
{
_in.Add(HandleCreate());
}
#if !SHIPPING
_out = new List<T>();
#endif
}
public T Get()
{
if (_in.Count == 0)
{
_in.Add(HandleCreate());
}
var item = _in.PopLast();
#if !SHIPPING
_out.Add(item);
#endif
return item;
}
public void Return( T item )
{
HandleReset(ref item);
#if !SHIPPING
Debug.Assert(!_in.Contains(item), "Returning an Item we already have.");
Debug.Assert(_out.Contains(item), "Returning an Item we never gave out.");
_out.Remove(item);
#endif
_in.Add(item);
}
public void Return( object item )
{
Return((T) item);
}
#if !SHIPPING
public void Validate()
{
Debug.Assert(_out.Count == 0, "An Item was not returned.");
}
#endif
}
接下来是一个多类型的池。
使用此类或自己使用多个Pool<T>
之间没有区别。但在某些情况下使用此类会使代码看起来更清晰,即。消除if/else (type == foo)
块。
/// <summary>
/// Represents a collection of pools for one or more object types.
/// </summary>
public class Pooler
{
private readonly List<IPool> _pools;
public Pooler()
{
_pools = new List<IPool>();
}
public void DefineType<T>(int initialCapacity, Pool<T>.Create createHandler, Pool<T>.Reset resetHandler)
{
var p = new Pool<T>(initialCapacity, createHandler, resetHandler);
_pools.Add(p);
}
public T Get<T>()
{
var p = GetPool(typeof (T));
if (p == null)
throw new Exception(string.Format("Pooler.Get<{0}>() failed; there is no pool for that type.", typeof(T)));
return ((Pool<T>)p).Get();
}
public void Return(object item)
{
var p = GetPool(item.GetType());
if (p == null)
throw new Exception(string.Format("Pooler.Get<{0}>() failed; there is no pool for that type.", item.GetType()));
p.Return(item);
}
private IPool GetPool(Type itemType)
{
foreach (var p in _pools)
{
if (p.ItemType == itemType)
{
return p;
}
}
return null;
}
}
就每次访问池时不必指定类型参数而言,我经常为经常使用的特定类型声明一个具体的池。
public class GameObjectPool : Pool<GameObject>
{
public GameObjectPool(int initialCapacity)
:base(initialCapacity, CreateObject, ResetObject)
{
}
private GameObject CreateObject()
{ ... }
private GameObject ResetObject()
{ ... }
}
然后你的代码是......
_pool = new Pool<GameObject>(10);
var obj = _pool.Get<GameObject>();
可以成为......
_pool = new GameObjectPool(10);
var obj = _pool.Get();
另一种选择是......
using GameObjectPool=MyRootnamespace.Pool<GameObject>
如果您对池有大量引用,但它们都在同一个代码文件中,那么它可以工作。