首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >责任链和泛型

责任链和泛型
EN

Stack Overflow用户
提问于 2020-07-07 02:45:13
回答 1查看 227关注 0票数 0

我有一个对集合应用过滤器的责任链。我正在尝试创建一个工厂,以便从配置中构建责任链。我的链的具体类型不是泛型的,但它们的抽象是泛型的,而泛型让我很难将它们放在一个集合中,以便在配置和正确的链节点实现之间进行映射。

下面是链的实现:

代码语言:javascript
复制
public interface IFilter<T> where T : IFilterable
{
    IFilter<T> SetNext(IFilter<T> next);
    IEnumerable<T> Filter(IEnumerable<T> data);
}

public class BaseFilter<T> : IFilter<T> where T : IFilterable
{
    protected IFilter<T> Next { get; set; }

    public IFilter<T> SetNext(IFilter<T> next)
    {
        Next = next;
        return Next;
    }

    public virtual IEnumerable<T> Filter(IEnumerable<T> data)
    {
        return Next == null ? data : Next.Filter(data);
    }
}

下面是链节点的具体实现示例:

代码语言:javascript
复制
public interface IFilterable {}

public interface ICanFly: IFilterable
{
    bool CanFly { get; }
}

public interface ITransport : IFilterable
{
    int Passengers { get; }
}

public class Duck : ICanFly
{
    public bool CanFly => true;
}

public class Plane : ICanFly, ITransport
{
    public bool CanFly => true;
    public int Passengers => 5;
}

public class FlyerFilter : BaseFilter<ICanFly>
{
    public override IEnumerable<ICanFly> Filter(IEnumerable<ICanFly> data)
    {
        return base.Filter(data.Where(x => x.CanFly));
    }
}

public class SmallTransportFilter : BaseFilter<ITransport>
{
    public override IEnumerable<ITransport> Filter(IEnumerable<ITransport> data)
    {
        return base.Filter(data.Where(x => x.Passengers < 8));
    }
}

当我想要创建一个将配置映射到我的具体类型(在我的示例中是FlyerFilterSmallTransportFilter )的工厂时,我的问题就开始了

代码语言:javascript
复制
public interface IFilterChainBuilder<T> where T : IFilterable
{
    IFilter<T> GenerateFilterResponsabilityChain(IEnumerable<string> filtersParam);
}

public class FilterChainBuilder<T> :  IFilterChainBuilder<T> where T : IFilterable
{


     private readonly Dictionary<string, IFilter<T>> _paramToFiltersMap;

     public FilterChainBuilder()
     {
         _paramToFiltersMap = new Dictionary<string, IFilter<T>>(StringComparer.OrdinalIgnoreCase)
         {
            {"Flyers",  new FlyerFilter()},                  // Compile error, cannot convert from FlyerFilter to IFilter<T>
            {"SmallTransport",  new SmallTransportFilter()}  // Compile error, cannot convert from SmallTransportFilter to IFilter<T>
         };
     }

     public IFilter<T> GenerateFilterResponsabilityChain(IEnumerable<string> filtersParam)
     {
         IFilter<T> filterResponsabilityChain = null;

         foreach (var parameter in filtersParam)
             if (_paramToFiltersMap.TryGetValue(parameter, out var filter))
             {
                  if (filterResponsabilityChain == null)
                      filterResponsabilityChain = filter;
                  else
                     filterResponsabilityChain.SetNext(filter);
            }
            else
            {
                 throw new ArgumentException(
                     $"config parameter {parameter} has no associated IFilter");
            }

         return filterResponsabilityChain ?? new BaseFilter<T>();
     }
}

我能理解为什么它不能编译。因为FlyerFilter是一个BaseFilter<ICanFly> (所以是一个IFilter<ICanFly>),所以如果我声明一个new FilterChainBuilder<PlaceholderType>会很糟糕。实际上,由于SmallTransportFilter继承自不同的T类型,因此唯一可能的IFilterable实现必须同时实现ITransportICanFly

我试图完全删除泛型T类型,但是这个响应链的使用者依赖于那个IEnumerable<T> Filter(IEnumerable<T> data)签名,并且想要一个具体类型的枚举,而不是IFilterable

我不知道如何解决这个问题,我现在被困在这里。

EN

回答 1

Stack Overflow用户

发布于 2020-07-07 04:29:00

IFilter是正确的-您对Pavel的定义使得类型参数T不变。抛开covariance/controvariance/invariance不谈,它的设计本身是有问题的。例如,FlyFilter只对ICanFly实例起作用,但是没有代码将输入过滤到ICanFly元素-这不应该也是FlyFilter的责任吗?我个人建议你直接在过滤器中使用类型信息,可能如下所示:

代码语言:javascript
复制
public interface IFilterable { }
public class CanFly : IFilterable { }
public class Duck : CanFly { }
public abstract class Transportation : CanFly
{
    public abstract int Passengers { get; }
}
public class Plane : Transportation
{
    public override int Passengers => 5;
}

public class FlyerFilter : BaseFilter<IFilterable>
{
    public override IEnumerable<IFilterable> Filter(IEnumerable<IFilterable> data)
    {
        return base.Filter(data.Where(x => x is CanFly));
    }
}

public class SmallTransportFilter : BaseFilter<IFilterable>
{
    public override IEnumerable<IFilterable> Filter(IEnumerable<IFilterable> data)
    {
        return base.Filter(data.Where(x => x is Transportation t && t.Passengers < 8));
    }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62762525

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档