4

What would be the point of making a constraint for an interface type on a generic in C#? For example,

public interface IHandler<in T>
    where T : IProcessor
{
    void Handle(T command);
}

Wouldn't it be better to simply inherit IProcessor as a generic without any constraints? What is the advantage of doing it this way?

For example,

public class FooProcessor : IProcessor<T>
{
    void Handle(T command)
    {
    }
}
Enigmativity
  • 113,464
  • 11
  • 89
  • 172
user1789573
  • 515
  • 2
  • 8
  • 23

2 Answers2

1

If the interface is blank then it is a marker interface.

It can be used for applying restrict about the class, outside of the class. In keeping with the example below you can restrict a decorator to only be able to decorate Handlers of IProcessor.


A very valid reason is when applying a decorator:

Let's say the command parameter interface has a couple of properties:

public interface IProcessor
{
    int Id { get; }
    DateTime Date { get; }
}

We can define a decorator over all handlers of IProcessor commands that have the knowledge that all the command parameters have Id and Date:

public sealed class HandlerLogger<in T> where T : IProcessor
{
    private readonly ILogger logger;
    private readonly IHandlerLogger<T> decorated;

    public HandlerLogger(
        ILogger logger,
        IHandlerLogger<T> decorated)
    {
        this.logger = logger;
        this.decorated = decorated;
    }

    public void Handle(T command)
    {
        this.logger.Log(command.Id, command.Date, typeof(T).Name);
        this.decorated.Handle(command);
    }
}
Community
  • 1
  • 1
qujck
  • 14,388
  • 4
  • 45
  • 74
  • Yeah, i get it if it's a concrete class AND that IProcessor has members declared. However, i'm using a project that's already been completed and am just trying to maintain the code. With that said--in my project the interface IProcessor is empty and the Handler is an interface (not that big of a deal). If IProcessor were empty what would be the advantage of making it a constraint? – user1789573 Jan 25 '16 at 18:59
  • 2
    In that case It's a [marker constraint](http://stackoverflow.com/questions/1023068/what-is-the-purpose-of-a-marker-interface) – qujck Jan 25 '16 at 19:02
0

There are different architectural patterns that can be used to pragmatically enforce types.
For example, if you were designing an API and you wanted to allow someone to extend it but you wanted to make sure that the class that was being created to extend your framework was a certain type and had a default parameterless constructor. Using generic typed interfaces is a common way to do this.

I have created a quick example adhoc to give a relatively simple overview of why a typed interface is useful in some models / architectural design.

public class UnitOfWorkManager<T>
{
    private readonly IDataRepository _dataRepository;
    private List<T> _unitOfWorkItems;

    public UnitOfWorkManager(IDataRepository dataRepository)
    {
        _dataRepository = dataRepository;
    }

    public void AddUnitOfWork(IUnitOfWork<T> unitOfWork)
    {
        this._unitOfWorkItems.Add(unitOfWork);
    }

    public void Execute()
    {
        WorkerItem previous = null;
        foreach (var item in _unitOfWorkItems)
        {
            var repoItem = _dataRepository.Get(item.Id);
            var input = new WorkerItem(item.Id, repoItem.Name, previous);
            previous = input;
        }
    }
}

public interface IUnitOfWork<T> 
    where T: WorkerItem, new()
{
    string Id { get; }
    void Execute(T input);
}

public class WorkerItem
{
    public WorkerItem(string id, string name, WorkerItem previous)
    {
        this.Name = name;
        this.Id = id;
        this.Previous = previous;
    }
    public string Id { get; private set; }
    public string Name { get; private set; }
    public WorkerItem Previous { get; private set; }
}

Hope this helps.

Jerrod Horton
  • 1,605
  • 1
  • 15
  • 30