0

在我的项目中;我已经包含了下面给出的特定模式类。我不知道如何实现这一点。这些代码由以前的开发人员包含。

public interface ISpecification<T>
{
    Expression<Func<T, bool>> SpecExpression { get; }
    bool IsSatisfiedBy(T obj);
}

public static class IExtensions
{
    public static ISpecification<T> And<T>(
        this ISpecification<T> left,
        ISpecification<T> right)
    {
        return new And<T>(left, right);
    }

    public static ISpecification<T> Or<T>(
        this ISpecification<T> left,
        ISpecification<T> right)
    {
        return new Or<T>(left, right);
    }

    public static ISpecification<T> Negate<T>(this ISpecification<T> inner)
    {
        return new Negated<T>(inner);
    }
}

public abstract class SpecificationBase<T> : ISpecification<T>
{
    private Func<T, bool> _compiledExpression;

    private Func<T, bool> CompiledExpression
    {
        get { return _compiledExpression ?? (_compiledExpression = SpecExpression.Compile()); }
    }

    public abstract Expression<Func<T, bool>> SpecExpression { get; }

    public bool IsSatisfiedBy(T obj)
    {
        return CompiledExpression(obj);
    }
}

public class And<T> : SpecificationBase<T>
{
    ISpecification<T> left;
    ISpecification<T> right;

    public And(
        ISpecification<T> left,
        ISpecification<T> right)
    {
        this.left = left;
        this.right = right;
    }

    // AndSpecification
    public override Expression<Func<T, bool>> SpecExpression
    {
        get
        {
            var objParam = Expression.Parameter(typeof(T), "obj");

            var newExpr = Expression.Lambda<Func<T, bool>>(
                Expression.AndAlso(
                    Expression.Invoke(left.SpecExpression, objParam),
                    Expression.Invoke(right.SpecExpression, objParam)
                ),
                objParam
            );

            return newExpr;
        }
    }
}

public class Or<T> : SpecificationBase<T>
{
    ISpecification<T> left;
    ISpecification<T> right;

    public Or(
        ISpecification<T> left,
        ISpecification<T> right)
    {
        this.left = left;
        this.right = right;
    }

    // OrSpecification
    public override Expression<Func<T, bool>> SpecExpression
    {
        get
        {
            var objParam = Expression.Parameter(typeof(T), "obj");

            var newExpr = Expression.Lambda<Func<T, bool>>(
                Expression.OrElse(
                    Expression.Invoke(left.SpecExpression, objParam),
                    Expression.Invoke(right.SpecExpression, objParam)
                ),
                objParam
            );

            return newExpr;
        }
    }
}

 public class Negated<T> : SpecificationBase<T>
{
    private readonly ISpecification<T> _inner;

    public Negated(ISpecification<T> inner)
    {
        _inner = inner;
    }

    // NegatedSpecification
    public override Expression<Func<T, bool>> SpecExpression
    {
        get
        {
            var objParam = Expression.Parameter(typeof(T), "obj");

            var newExpr = Expression.Lambda<Func<T, bool>>(
                Expression.Not(
                    Expression.Invoke(this._inner.SpecExpression, objParam)
                ),
                objParam
            );

            return newExpr;
        }
    }
}

如何用一个简单的例子来实现上述规范?这个规范有什么用?

4

1 回答 1

0

正如我在评论中所写,这是借助Expression.

假设我们有以下领域模型:

public class Person
{
    public string Name { get; set; }
    public DateTime BirthDate { get; set; }
    public string Country { get; set; }
}

而且,我们还有一个列表:

List<Person> persons; // <-- initialized elsewhere

现在我们可以为它们制定两个规范。让我们有一个给那些住在里面的Spain人和一个给那些以前出生的人01/01/2000

public class SpainSpec : SpecificationBase<Person>
{
    public override Expression<Func<Person, bool>> SpecExpression => person => person.Country == "Spain";
}

public class BornBefore2000 : SpecificationBase<Person>
{
    public override Expression<Func<Person, bool>> SpecExpression => person => person.BirthDate < DateTime.Parse("2000-01-01");
}

现在我们可以用它来查找所有在 2000 年之前出生的人:

ISpecification spec = new SpainSpec();
persons.Where (spec.IsSatisfiedBy);

您当然可以将它们链接起来以获取 2000 年之前出生的西班牙人:

ISpecification spec = new SpainSpec().And(new BornBefore2000());
persons.Where (spec.IsSatisfiedBy);

这确实是一个非常简单的场景,您可以拥有更多场景,具体取决于您的模型和需求。

使用规范时要小心,这样您就不会失去对它的控制并且有太多的类或发现自己重新发明了轮子。

于 2017-03-01T12:09:43.630 回答