Can I use raw type in C# like Java or is there a workaround for this? I know using Raw Type in Java is bad practice but that can solve my current problem. I have an object that has a field holding a Pool, so that it can return to that Pool whenever it's done with its job.
//C#
public class MyObject : IPoolable
{
public Pool<MyObject> pool;
}
But if there is a new kind of object (ex: MovableObject
), I want my pool
field has Pool<MovableObject>
not Pool<MyObject>
. (There are also many kinds of objects derived from MovableObject
or MyObject
).
In Java, I could define pool
field a raw type of Pool
so that there is no compiling error.
//Java
public class MyObject implements IPoolable
{
public Pool pool;
}
I'm using a method to return all kinds sof objects in both versions. In Java, it works well but in C#, it has compiling error.
//Java
static public <T extends MyObject> T createObject(Class<T> type) {
Pool<T> pool = Pools.get(type);
T obj= pool.obtain();
obj.setPool(pool); //This won't have any problem since it is raw type
return obj;
}
//C#
public static T CreateObject<T>() where T : MyObject
{
Pool<T> pool = Pools.GetPool<T>();
T obj= pool.Obtain();
obj.Pool = pool; //Error: cannot convert Pool<T> to Pool<MyAction>
return obj;
}
Edit 1: Providing other classes and Minimal, Reproducible Example
public interface IPoolable
{
void Reset();
}
public abstract class Pool<T> where T : IPoolable
{
private readonly Stack<T> freeObjects = new Stack<T>();
public Pool() { }
protected abstract T InstantiateObject(object[] args);
public T Obtain(object[] args = null)
{
return freeObjects.Count == 0 ? InstantiateObject(args) : freeObjects.Pop();
}
public void Free(T obj)
{
if (obj != null)
{
freeObjects.Push(obj);
Reset(obj);
}
}
protected virtual void Reset(T obj)
{
obj.Reset();
}
public void Clear()
{
freeObjects.Clear();
}
}
//ReflectionPool
public class ReflectionPool<T> : Pool<T> where T : IPoolable
{
public ReflectionPool() : base()
{
}
protected override T InstantiateObject(object[] args)
{
return (T)Activator.CreateInstance(typeof(T), args);
}
}
public class Pools
{
static private readonly Dictionary<Type, object> typePools = new Dictionary<Type, object>();
static public Pool<T> GetPool<T>(int max) where T : IPoolable
{
Type type = typeof(T);
if (!typePools.TryGetValue(type, out object pool))
{
pool = new ReflectionPool<T>();
typePools.Add(type, pool);
}
return (Pool<T>)pool;
}
static public Pool<T> GetPool<T>() where T : IPoolable
{
return GetPool<T>(100);
}
}
So in MyObject
class, there is a method making my object doing something, after completing it, the current object need to be returned to Pool
//Base Object
public abstract class MyObject : IPoolable
{
public Pool<MyObject> pool; //This is still a problem
public void CallMe()
{
if (Act()) //If this object completing acting
{
ToPool();
}
}
public abstract bool Act();
public void ToPool()
{
pool.Free(this);
pool = null;
}
public abstract void Reset();
}
//Movable Object
public class MovableObject : MyObject
{
//public Pool<MyObject> pool; //Put this here as comment because I want it become Pool<MovableObject>
public override bool Act()
{
return true; //Return false if not reach destination
}
public override void Reset() { }
public override string ToString()
{
return "Movable";
}
}
//I'm using this class for create object I want
public class ObjectFactory
{
public static T CreateObject<T>() where T : MyObject
{
Pool<T> pool = Pools.GetPool<T>();
if(pool != null)
{
T obj = pool.Obtain();
obj.pool = pool; //Error here: Cannot implicitly convert type 'Pool<T>' to 'Pool<MyObject>'
return obj;
}
return null;
}
public static MovableObject MovableObject()
{
return CreateObject<MovableObject>();
}
}
Edit 2: Re-Updated code in edit 1
IPoolable
,Pool<T>
, andPools
. – Enigmativitydynamic
is a good answer. – EnigmativityIPool<out T>
? – Johnathan Barclay