创建一个泛型类池,在其中提供泛型参数并获取使用该参数的泛型对象

Geo*_*ett 3 c# generics generic-type-argument object-pooling

目标

我有一个通用类GenericClass<T>,我想池化实例。
我有兴趣看看是否可以获得语法:

MyGenericPool = new GenericPool<GenericClass>();
// Or maybe it's MyGenericPool = new GenericPool<GenericClass<>>();

GenericClass<TGenericParam> GenericClassInstance =
    MyGenericPool.Get<TGenericParam>();
Run Code Online (Sandbox Code Playgroud)

(我对泛型的理解是,不,我不能,别傻了,语法不存在/不起作用,但我对其他人的想法很感兴趣)。


展示我的作品

我有点怀疑,因为从我对类型的理解来看,从类型系统的角度来看,它们并没有真正相关GenericClass<string>GenericClass<int>

现在,我意识到我可以接近,即:

GenericClass<TGenericParam> GenericClassInstance =
    GenericPool.Get<GenericClass<TGenericParam>>();
Run Code Online (Sandbox Code Playgroud)

然后把它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>;
    }
}
Run Code Online (Sandbox Code Playgroud)

问题

我可以获得我想要的语法(在顶部)吗?如果没有,我能接近多远?

Dan*_*rth 5

您尝试实现的解决方案/语法无法以这种方式工作,因为您无法使用没有类型参数的泛型类型作为另一个泛型类型的类型参数。

但是,您可以通过以下方法获得类似的结果:

  1. 为类池创建一个基类,要求您提供完整的泛型类型
  2. 为特定泛型类型创建派生类

像这样的东西:

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>>();
    }
}
Run Code Online (Sandbox Code Playgroud)

那么用法将是这样的:

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>();
Run Code Online (Sandbox Code Playgroud)

此解决方案的缺点是,您需要为要池化的每个泛型类型创建一个池类,因此您可能会拥有许多<className>PoolObjectPool.
为了使其可用,所有实际代码都需要位于类中ObjectPool,并且只有提供通用参数的代码保留在派生类中。