Search code examples
c#genericscovariancecontravariance

Casting Generic to abstract base - covariance


The code below gives compile time error:

Error 170 Cannot convert type 'Tests.ChangeListener' to 'Tests.BaseListener'

How do I get this to compile?

namespace Tests
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void ShouldCompile()
        {
            BaseListener<IChange> listener = (BaseListener<IChange>)new ChangeListener();
        }
    }

    public interface IChange
    {
    }

    public interface ISpecificChange : IChange
    {   
    }

    public abstract class BaseListener<T> 
    where T : IChange
    {       
    }

    public class ChangeListener : BaseListener<ISpecificChange>
    {
    }
}   

Solution

  • Since you can't do contravariance or covaraiance (ie in and out) on an abstract class you'll probably want an interface for your listener. Modifying the above to look like this allows it to compile (note entities not mentioned remain the same as the original code - attributes stripped to save me needing to import references while testing):

    public class UnitTest1
    {
        public void ShouldCompile()
        {
            IListener<IChange> listener = new ChangeListener();
        }
    }
    
    
    public interface IListener<out T> {}
    
    public abstract class BaseListener<T> : IListener<T>
    where T : IChange
    {       
    }
    

    This is obviously adding in a step that you don't currently have and may not be able to use for whatever reasons but it is the simplest way to get the code compiling and I think do what you want.