我有一个对集合应用过滤器的责任链。我正在尝试创建一个工厂,以便从配置中构建责任链。我的链的具体类型不是泛型的,但它们的抽象是泛型的,而泛型让我很难将它们放在一个集合中,以便在配置和正确的链节点实现之间进行映射。
下面是链的实现:
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);
}
}
下面是链节点的具体实现示例:
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));
}
}
当我想要创建一个将配置映射到我的具体类型(在我的示例中是FlyerFilter
和SmallTransportFilter
)的工厂时,我的问题就开始了
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
实现必须同时实现ITransport
和ICanFly
。
我试图完全删除泛型T类型,但是这个响应链的使用者依赖于那个IEnumerable<T> Filter(IEnumerable<T> data)
签名,并且想要一个具体类型的枚举,而不是IFilterable
。
我不知道如何解决这个问题,我现在被困在这里。
发布于 2020-07-06 20:29:00
IFilter是正确的-您对Pavel的定义使得类型参数T不变。抛开covariance/controvariance/invariance不谈,它的设计本身是有问题的。例如,FlyFilter只对ICanFly实例起作用,但是没有代码将输入过滤到ICanFly元素-这不应该也是FlyFilter的责任吗?我个人建议你直接在过滤器中使用类型信息,可能如下所示:
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));
}
}
https://stackoverflow.com/questions/62762525
复制相似问题