我有规范模式实现,我想改变它以支持逆变。然而,出现了一个有趣的问题。
public interface ISpecification<in T>
{
Func<T, bool> Predicate { get; }
bool IsSatisfiedBy(T entity);
}
public class Specification<T> : ISpecification<T>
{
public Specification(Func<T, bool> predicate)
{
this.Predicate = predicate;
}
public Func<T, bool> Predicate
{
get;
private set;
}
public bool IsSatisfiedBy(T x)
{
return Predicate.Invoke(x);
}
public static Specification<T> operator &(Specification<T> left, ISpecification<T> right)
{
return new Specification<T>((x) => left.Predicate(x) && right.Predicate(x));
}
}
你可以期待的这项工作
new Specification<DerivedClass>((x) => true) & new Specification<BaseClass> ((x) => true)
但是如果我颠倒了参数的顺序,它就不再编译了
new Specification<BaseClass>((x) => true) & new Specification<DerivedClass>((x) => true)
我理解为什么会发生这种情况,但我的问题是 - 有没有办法让两者兼得?
编辑:
我已经尝试定义operator&amp;反向顺序或类似的参数
public static Specification<T> operator &(ISpecification<T> left, Specification<T> right)
{
return new Specification<T>((x) => left.Predicate(x) && right.Predicate(x));
}
但是我在两个运营商之间调用编译器错误是模糊的。我使用的是.NET 4.5
netfiddle:https://dotnetfiddle.net/GB66UN
答案 0 :(得分:6)
是 - 只需再次为其他参数订单执行此操作。
public static Specification<T> operator &(ISpecification<T> left, Specification<T> right)
{
return new Specification<T>((x) => left.Predicate(x) && right.Predicate(x));
}
运算符重载不要求第一个参数属于封闭类型,只需一个参数。
AS @DStanley指出,即使这会在表格
的调用中失败new Specification<DerivedClass>((x) => true) & new Specification<DerivedClass>((x) => true);
所以我们再做一次,对于这个特定的参数组合:
public static Specification<T> operator &(Specification<T> left, Specification<T> right)
{
return new Specification<T>((x) => left.Predicate(x) && right.Predicate(x));
}
答案 1 :(得分:2)
支持Covariance&amp;你需要像这样重载运算符的逆变量
public static Specification<T> operator &(ISpecification<T> left, Specification<T> right)
{
return new Specification<T>((x) => left.Predicate(x) && right.Predicate(x));
}
public static Specification<T> operator &(Specification<T> left, ISpecification<T> right)
{
return new Specification<T>((x) => left.Predicate(x) && right.Predicate(x));
}
public static Specification<T> operator &(Specification<T> left, Specification<T> right)
{
return new Specification<T>((x) => left.Predicate(x) && right.Predicate(x));
}