逆变和操作员过载

时间:2016-04-21 13:22:28

标签: c# generics c#-4.0

我有规范模式实现,我想改变它以支持逆变。然而,出现了一个有趣的问题。

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

2 个答案:

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