为什么要限制泛型键入界面?

时间:2016-01-25 18:43:38

标签: c# generics constraints covariance contravariance

在C#中对泛型的接口类型进行约束有什么意义?例如,

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

在没有任何约束的情况下简单地将IProcessor作为通用继承是不是更好?这样做有什么好处?

例如,

public class Test: IProcessor<T>{void Handle(T command);}

2 个答案:

答案 0 :(得分:1)

如果界面为空,则为marker interface

它可以用于在课堂外对类进行限制。根据下面的示例,您可以限制装饰器只能装饰IProcessor的处理程序。

一个非常正当的理由是在申请装饰时:

让我们说命令参数界面有几个属性:

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

我们可以在IProcessor个命令的所有处理程序上定义装饰器,这些命令知道所有命令参数都有IdDate

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);
    }
}

答案 1 :(得分:0)

可以使用不同的架构模式来实际执行类型 例如,如果您正在设计API并且希望允许某人扩展它,但您希望确保为扩展框架而创建的类是某种类型并且具有默认的无参数构造函数。使用泛型类型接口是执行此操作的常用方法。

我已经创建了一个快速示例adhoc,以便相对简单地概述为什么类型化接口在某些模型/架构设计中有用。

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; }
}

希望这有帮助。