C#
Beginner
1 min read
Generic Interfaces and Covariance
Example
// Generic interfaces, covariance, and interface segregation
// Generic repository interface
public interface IRepository<T> where T : class
{
T? GetById(int id);
IList<T> GetAll();
void Add(T entity);
void Remove(int id);
}
// Covariant interface — T can only appear as output (out)
public interface IProducer<out T>
{
T Produce();
}
// Contravariant interface — T can only appear as input (in)
public interface IConsumer<in T>
{
void Consume(T item);
}
// Demonstrating covariance assignment
public class AnimalProducer : IProducer<string>
{
public string Produce() => "Cat";
}
IProducer<string> stringProducer = new AnimalProducer();
IProducer<object> objectProducer = stringProducer; // covariance — works!
Console.WriteLine(objectProducer.Produce()); // "Cat"
// Interface segregation — split large interface
public interface IReadable<T> { T Read(int id); }
public interface IWritable<T> { void Write(T item); }
public interface IReadWrite<T> : IReadable<T>, IWritable<T> { }
// A read-only view can depend on just IReadable
public class ReportGenerator<T>
{
private readonly IReadable<T> _store;
public ReportGenerator(IReadable<T> store) => _store = store;
public void Generate(int id) => Console.WriteLine(_store.Read(id)?.ToString());
}