I have the following code written in c# using interfaces, inheritance and generics:
public interface IBasic
{
}
public class Basic : IBasic
{
}
public class AnotherBasic : Basic
{
}
public interface IWorker<in TBasic>
{
void Run(TBasic basic);
}
public class Worker : IWorker<Basic>
{
public void Run(Basic basic)
{
throw new System.NotImplementedException();
}
}
public class AnotherWorker : IWorker<AnotherBasic>
{
public void Run(AnotherBasic basic)
{
throw new System.NotImplementedException();
}
}
public void Test()
{
List<IWorker<IBasic>> workers = new List<IWorker<IBasic>>
{
new Worker(),
new AnotherWorker()
};
}
The problem of this code is that the worker and anotherworker classes do not fit in to the generics list of IWorker<IBasic>
who are the parents of workers for both the worker and the basic class. The thing is that IWorker<in TBasic>
is contravariant because of run method signature, however I need it covariant, in order to fill in the List<IWorker<IBasic>>
. The run method has to have the TBasic parameter, and I need this list of workers on purpose of chain of responsibility design pattern. Do I miss something or did I find a reason to make covariance and contravariance not mutually exclusive ?
So after 2 days of learning and investigation I answered my own question. Here is the code:
public interface IBasic {
}
public class Basic : IBasic
{
}
public class AnotherBasic : Basic
{
}
public interface IWorker<in TBasic>
{
void Run(TBasic basic);
}
public class SimpleWorker : IWorker<IBasic>
{
public void Run(IBasic basic)
{
throw new System.NotImplementedException();
}
}
public class Worker : IWorker<Basic>
{
public void Run(Basic basic)
{
throw new System.NotImplementedException();
}
}
public class AnotherWorker : IWorker<AnotherBasic>
{
public void Run(AnotherBasic basic)
{
throw new System.NotImplementedException();
}
}
public class Final
{
public void Test()
{
List<IWorker<AnotherBasic>> workers = new List<IWorker<AnotherBasic>>
{
new SimpleWorker(),
new Worker(),
new AnotherWorker()
};
}
}
TBasic in CONTRAVARIANT, which means the declaration should be the most specific as possible, as shown in the code: AnotherBasic Then the types that are less derived, are the parents, are accepted, and the code compiles.