Instantiating an object from its interface

I have created a generic object pooling script which I intend to reuse. From a design standpoint, I thought it would be best to go with a Pool class, which can be inherited from, and an IPoolable interface, which specifies the contract that poolable objects would have to fulfill. Here are the relevant parts:

public interface IPoolable {
	bool IsIncarnate();
	void Incarnate(Vector3 position, Quaternion rotation, Vector3 scale);	//Called when the object is checked out from the pool
	void Relinquish();	//Called to return the object to the pool.
}

and

public class Pool : MonoBehaviour {
	public int count = 256;	
	public IPoolable pooledObj;
	public List<IPoolable> allObj;
	//snip some irrelevant stuff

	protected virtual void Start() {
		allObj = new List<IPoolable>(count);
		InstantiatePool();
	}

	protected virtual void InstantiatePool() {
		for (int i = 0; i < count; i++) {
			allObj.Add((IPoolable)Instantiate(pooledObj));
			allObj*.Relinquish();*
  •  }*
    
  • }*

  • public IPoolable GetNext() {*

  •  IPoolable next = allObj.Find(x => !x.IsIncarnate());*
    
  •  //snip behavior of what to do when full*
    
  •  return next;*
    
  • }*
    }

The issue I was having was with this line:
allObj.Add((IPoolable)Instantiate(pooledObj));
The problem is that Instantiate requires a UnityEngine.Object. IPoolable is an interface, so it seems that, even though it is always attached to an Object, which can be instantiated, the compiler doesn’t know that.
I did come up with a solution, which was to change IPoolable from an interface into an abstract class, called Poolable:
public abstract class Poolable : MonoBehaviour {

  • public virtual bool IsIncarnate { get { return gameObject.activeInHierarchy; } }*

  • public abstract void Incarnate(Vector3 position, Quaternion rotation, Vector3 scale); //Called when the object is checked out from the pool*

  • public virtual void Relinquish() { //Called to return the object to the pool.*

  •  gameObject.SetActive(false);*
    
  • }*
    }
    Because this class inherits from MonoBehavior, it fulfills the condition that Instantiate must accept an Object argument. However, from a design perspective this feels wrong - it seems to me that I really only want to specify a contract in Poolable, so I should be using an interface. What would happen, for example, if I need an object to be both poolable and inherit from another MonoBehavior? This solution would make that impossible, because only one class can be inherited from - although multiple interfaces can be implemented.
    So my question - is there a way to make that problem line work? A way that I can instantiate the object even though I have a handle on it by the IPoolable interface?

It’s a matter of taste but…
Your interface acts as a contract to guarantee its implementations are suitable for pooling.
However the interface can not guarantee that the implementing class can be instantiated.
If it really is a requirement that IPoolables have to be Instantiate()d, it would maybe make sense to make it a part of the contract: i.e. add a function UnityEngine.Object GetObjectToInstantiate(); or such to you
interface and most of the time make its implementations return this.

This is not a clean solution, but if you can be 100% sure that every IPoolable will be derived from MonoBehaviour in some way, you can use it:

allObj.Add((IPoolable)Instantiate((UnityEngine.Object)((object)pooledObj)));

It’s basically operating on that assumption to cast spoof the instantiator.

There’s actually a very cool way of doing it. It keeps things super decoupled (which is surprising given with what singletons are), take a look at the thread i made on the forums

Code Design: Abstracting Singletons

it’s a little secret, but you can actually make extension methods for interfaces!

which is super cool cause you can do something like make a singleton class and have your entire project use it without ever calling the concrete class.