Search code examples
c#genericscasting

Casting to arbitrary version of generic class


I have a class as follows:

public class Impactable<T> : where T : Spawnable<T>
{
    protected T spawnable = Spawnable<T>.Instance;

    void DoSomethingIndependentOfT(){}
}

The reason I have it implemented like this is because Spawnable is a Lazy extendable Singleton. In Impactable, I have of course methods that utilize spawnable, but also methods that don't that I'd like to access externally by casting.

public sealed class EnemySpawnable : Spawnable<EnemySpawnable>
{
}

public class MyEnemyA : Impactable<EnemySpawnable>
{
}

MyEnemyA enemy = new MyEnemyA();
Impactable x = enemy;
x.DoSomethingIndependentOfT();

Is it possible to achieve a cast like this in C# or will I have to re-engineer my code?


Solution

  • No, its not. The type argument constraint on Impactable (where) prevents it. But the refactoring required is non-breaking and trivial. The solution is to promote the type-independent methods to a base class which does not require specialization, like so:

    public class Spawnable<T>
    {
        public static T Instance;
    }
    
    public class Impactable
    {
        internal void DoSomethingIndependentOfT() { }
    }
    
    public class Impactable<T> : Impactable where T : Spawnable<T>
    {
        protected T spawnable = Spawnable<T>.Instance;
    }
    
    public sealed class EnemySpawnable : Spawnable<EnemySpawnable>
    {
    }
    
    public class MyEnemyA : Impactable<EnemySpawnable>
    {
    }
    
    public class Program
    {
        public static void Main()
        {
            MyEnemyA enemy = new MyEnemyA();
            Impactable x = enemy;
            x.DoSomethingIndependentOfT();
        }
    }
    

    Even if what you intended would be possible (or is made possible in future versions of C#), it's still much cleaner to do it this way, because it self-documents the intent (methods that do not use generics, should not reside in a container scoped to a constrained type).