2016-04-21 47 views
5

我有规范模式的实现,我想改变它以支持逆变。然而有趣的问题出现了。逆变和操作超负荷

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) 

我理解为什么会这样,但我的问题是 - 有没有办法兼顾工作?

编辑:

我已经尝试过定义操作&逆序或PARAMS既像运营商之间的

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

回答

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

我已经试过,但我得到两个运营商之间的模糊呼叫 – ekalchev

+0

有趣的,这可能是一个版本不匹配。我在LINQPad 5中工作,该工具的目标是.NET 4.6并使用C#6.我知道重载解析的实现看到了变化。 –

+2

LINQPad 4(.NET 4.5)也接受这一点。您能否显示提供错误的完整代码 - 特别是在两个过载都存在后失败的调用? –

2

要同时支持协方差&您需要像这样超载运营商的逆变量

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