This commit is contained in:
2025-06-30 19:22:02 +08:00
commit a2e0ca09a6
2663 changed files with 1367889 additions and 0 deletions

View File

@@ -0,0 +1,36 @@
using System;
using System.Linq.Expressions;
namespace MyCode.Project.Infrastructure
{
/// <summary>
/// Represents the combined specification which indicates that the first specification
/// can be satisifed by the given object whereas the second one cannot.
/// </summary>
/// <typeparam name="T">The type of the object to which the specification is applied.</typeparam>
public class AndNotSpecification<T> : CompositeSpecification<T>
{
#region Ctor
/// <summary>
/// Constructs a new instance of <c>AndNotSpecification&lt;T&gt;</c> class.
/// </summary>
/// <param name="left">The first specification.</param>
/// <param name="right">The second specification.</param>
public AndNotSpecification(ISpecification<T> left, ISpecification<T> right) : base(left, right) { }
#endregion
#region Public Methods
/// <summary>
/// Gets the LINQ expression which represents the current specification.
/// </summary>
/// <returns>The LINQ expression.</returns>
public override Expression<Func<T, bool>> GetExpression()
{
var bodyNot = Expression.Not(Right.GetExpression().Body);
var bodyNotExpression = Expression.Lambda<Func<T, bool>>(bodyNot, Right.GetExpression().Parameters);
return Left.GetExpression().And(bodyNotExpression);
}
#endregion
}
}

View File

@@ -0,0 +1,36 @@
using System;
using System.Linq.Expressions;
namespace MyCode.Project.Infrastructure
{
/// <summary>
/// Represents the combined specification which indicates that both of the given
/// specifications should be satisfied by the given object.
/// </summary>
/// <typeparam name="T">The type of the object to which the specification is applied.</typeparam>
public class AndSpecification<T> : CompositeSpecification<T>
{
#region Ctor
/// <summary>
/// Constructs a new instance of <c>AndSpecification&lt;T&gt;</c> class.
/// </summary>
/// <param name="left">The first specification.</param>
/// <param name="right">The second specification.</param>
public AndSpecification(ISpecification<T> left, ISpecification<T> right) : base(left, right) { }
#endregion
#region Public Methods
/// <summary>
/// Gets the LINQ expression which represents the current specification.
/// </summary>
/// <returns>The LINQ expression.</returns>
public override Expression<Func<T, bool>> GetExpression()
{
//var body = Expression.AndAlso(Left.GetExpression().Body, Right.GetExpression().Body);
//return Expression.Lambda<Func<T, bool>>(body, Left.GetExpression().Parameters);
return Left.GetExpression().And(Right.GetExpression());
}
#endregion
}
}

View File

@@ -0,0 +1,25 @@

using System;
using System.Linq.Expressions;
namespace MyCode.Project.Infrastructure
{
/// <summary>
/// Represents the specification that can be satisfied by the given object
/// in any circumstance.
/// </summary>
/// <typeparam name="T">The type of the object to which the specification is applied.</typeparam>
public sealed class AnySpecification<T> : Specification<T>
{
#region Public Methods
/// <summary>
/// Gets the LINQ expression which represents the current specification.
/// </summary>
/// <returns>The LINQ expression.</returns>
public override Expression<Func<T, bool>> GetExpression()
{
return o => true;
}
#endregion
}
}

View File

@@ -0,0 +1,45 @@

namespace MyCode.Project.Infrastructure
{
/// <summary>
/// Represents the base class for composite specifications.
/// </summary>
/// <typeparam name="T">The type of the object to which the specification is applied.</typeparam>
public abstract class CompositeSpecification<T> : Specification<T>, ICompositeSpecification<T>
{
#region Private Fields
private readonly ISpecification<T> left;
private readonly ISpecification<T> right;
#endregion
#region Ctor
/// <summary>
/// Constructs a new instance of <c>CompositeSpecification&lt;T&gt;</c> class.
/// </summary>
/// <param name="left">The first specification.</param>
/// <param name="right">The second specification.</param>
public CompositeSpecification(ISpecification<T> left, ISpecification<T> right)
{
this.left = left;
this.right = right;
}
#endregion
#region ICompositeSpecification Members
/// <summary>
/// Gets the first specification.
/// </summary>
public ISpecification<T> Left
{
get { return this.left; }
}
/// <summary>
/// Gets the second specification.
/// </summary>
public ISpecification<T> Right
{
get { return this.right; }
}
#endregion
}
}

View File

@@ -0,0 +1,113 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
namespace MyCode.Project.Infrastructure
{
/// <summary>
/// Represents the extender for Expression[Func[T, bool]] type.
/// This is part of the solution which solves
/// the expression parameter problem when going to Entity Framework by using
/// Apworks specifications. For more information about this solution please
/// </summary>
public static class ExpressionFuncExtender
{
#region Private Methods
private static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge)
{
// build parameter map (from parameters of second to parameters of first)
var map = first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }).ToDictionary(p => p.s, p => p.f);
// replace parameters in the second lambda expression with parameters from the first
var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body);
// apply composition of lambda expression bodies to parameters from the first expression
return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters);
}
#endregion
#region Public Methods
/// <summary>
/// Combines two given expressions by using the AND semantics.
/// </summary>
/// <typeparam name="T">The type of the object.</typeparam>
/// <param name="first">The first part of the expression.</param>
/// <param name="second">The second part of the expression.</param>
/// <returns>The combined expression.</returns>
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
{
return first.Compose(second, Expression.And);
}
/// <summary>
/// Combines two given expressions by using the OR semantics.
/// </summary>
/// <typeparam name="T">The type of the object.</typeparam>
/// <param name="first">The first part of the expression.</param>
/// <param name="second">The second part of the expression.</param>
/// <returns>The combined expression.</returns>
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
{
return first.Compose(second, Expression.Or);
}
/// <summary>
/// 创建一个Lambda表达式
/// </summary>
/// <typeparam name="T">实体类型</typeparam>
/// <param name="prop">实体属性</param>
/// <param name="value">属性值</param>
/// <param name="valueType">属性值的数据类型</param>
/// <returns></returns>
public static Expression<Func<T, bool>> CreateLambda<T>(string prop, object value, Type valueType = null)
{
var parameter = Expression.Parameter(typeof(T), "t");
Expression property = null;
string[] props = prop.Split('.');
for (int i = 0; i < props.Length; i++)
{
if (property == null)
{
property = Expression.Property(parameter, props[i]);
}
else
{
property = Expression.Property(property, props[i]);
}
}
var body = Expression.Equal(property, valueType != null ? Expression.Constant(value, valueType) : Expression.Constant(value));
var lambda = Expression.Lambda<Func<T, bool>>(body, parameter);
return lambda;
}
/// <summary>
/// 创建一个Lambda表达式
/// </summary>
/// <typeparam name="T">实体类型</typeparam>
/// <param name="prop">实体属性</param>
/// <param name="value">属性值</param>
/// <param name="valueType">属性值的数据类型</param>
/// <returns></returns>
public static Expression<Func<object, bool>> CreateLambda(Type t, string prop, object value, Type valueType = null)
{
var parameter = Expression.Parameter(t, "t");
Expression property = null;
string[] props = prop.Split('.');
for (int i = 0; i < props.Length; i++)
{
if (property == null)
{
property = Expression.Property(parameter, props[i]);
}
else
{
property = Expression.Property(property, props[i]);
}
}
var body = Expression.Equal(property, valueType != null ? Expression.Constant(value, valueType) : Expression.Constant(value));
var lambda = Expression.Lambda<Func<object, bool>>(body, Expression.Parameter(typeof(object), "t"));
return lambda;
}
#endregion
}
}

View File

@@ -0,0 +1,41 @@

using System;
using System.Linq.Expressions;
namespace MyCode.Project.Infrastructure
{
/// <summary>
/// Represents the specification which is represented by the corresponding
/// LINQ expression.
/// </summary>
/// <typeparam name="T">The type of the object to which the specification is applied.</typeparam>
internal sealed class ExpressionSpecification<T> : Specification<T>
{
#region Private Fields
private Expression<Func<T, bool>> expression;
#endregion
#region Ctor
/// <summary>
/// Initializes a new instance of <c>ExpressionSpecification&lt;T&gt;</c> class.
/// </summary>
/// <param name="expression">The LINQ expression which represents the current
/// specification.</param>
public ExpressionSpecification(Expression<Func<T, bool>> expression)
{
this.expression = expression;
}
#endregion
#region Public Methods
/// <summary>
/// Gets the LINQ expression which represents the current specification.
/// </summary>
/// <returns>The LINQ expression.</returns>
public override Expression<Func<T, bool>> GetExpression()
{
return this.expression;
}
#endregion
}
}

View File

@@ -0,0 +1,19 @@

namespace MyCode.Project.Infrastructure
{
/// <summary>
/// Represents that the implemented classes are composite specifications.
/// </summary>
/// <typeparam name="T">The type of the object to which the specification is applied.</typeparam>
public interface ICompositeSpecification<T> : ISpecification<T>
{
/// <summary>
/// Gets the left side of the specification.
/// </summary>
ISpecification<T> Left { get; }
/// <summary>
/// Gets the right side of the specification.
/// </summary>
ISpecification<T> Right { get; }
}
}

View File

@@ -0,0 +1,62 @@

using System;
using System.Linq.Expressions;
namespace MyCode.Project.Infrastructure
{
/// <summary>
/// Represents that the implemented classes are specifications. For more
/// information about the specification pattern, please refer to
/// http://martinfowler.com/apsupp/spec.pdf.
/// </summary>
/// <typeparam name="T">The type of the object to which the specification
/// is applied.</typeparam>
public interface ISpecification<T>
{
/// <summary>
/// Returns a <see cref="System.Boolean"/> value which indicates whether the specification
/// is satisfied by the given object.
/// </summary>
/// <param name="obj">The object to which the specification is applied.</param>
/// <returns>True if the specification is satisfied, otherwise false.</returns>
bool IsSatisfiedBy(T obj);
/// <summary>
/// Combines the current specification instance with another specification instance
/// and returns the combined specification which represents that both the current and
/// the given specification must be satisfied by the given object.
/// </summary>
/// <param name="other">The specification instance with which the current specification
/// is combined.</param>
/// <returns>The combined specification instance.</returns>
ISpecification<T> And(ISpecification<T> other);
/// <summary>
/// Combines the current specification instance with another specification instance
/// and returns the combined specification which represents that either the current or
/// the given specification should be satisfied by the given object.
/// </summary>
/// <param name="other">The specification instance with which the current specification
/// is combined.</param>
/// <returns>The combined specification instance.</returns>
ISpecification<T> Or(ISpecification<T> other);
/// <summary>
/// Combines the current specification instance with another specification instance
/// and returns the combined specification which represents that the current specification
/// should be satisfied by the given object but the specified specification should not.
/// </summary>
/// <param name="other">The specification instance with which the current specification
/// is combined.</param>
/// <returns>The combined specification instance.</returns>
ISpecification<T> AndNot(ISpecification<T> other);
/// <summary>
/// Reverses the current specification instance and returns a specification which represents
/// the semantics opposite to the current specification.
/// </summary>
/// <returns>The reversed specification instance.</returns>
ISpecification<T> Not();
/// <summary>
/// Gets the LINQ expression which represents the current specification.
/// </summary>
/// <returns>The LINQ expression.</returns>
Expression<Func<T, bool>> GetExpression();
}
}

View File

@@ -0,0 +1,20 @@

namespace MyCode.Project.Infrastructure
{
/// <summary>
/// Represents that the implemented classes are specification parsers that
/// parses the given specification to a domain specific criteria object, such
/// as the <c>ICriteria</c> instance in NHibernate.
/// </summary>
/// <typeparam name="TCriteria">The type of the domain specific criteria.</typeparam>
public interface ISpecificationParser<TCriteria>
{
/// <summary>
/// Parses the given specification to a domain specific criteria object.
/// </summary>
/// <typeparam name="T">The type of the object to which the specification is applied.</typeparam>
/// <param name="specification">The specified specification instance.</param>
/// <returns>The instance of the domain specific criteria.</returns>
TCriteria Parse<T>(ISpecification<T> specification);
}
}

View File

@@ -0,0 +1,25 @@

using System;
using System.Linq.Expressions;
namespace MyCode.Project.Infrastructure
{
/// <summary>
/// Represents the specification that can be satisfied by the given object
/// in no circumstance.
/// </summary>
/// <typeparam name="T">The type of the object to which the specification is applied.</typeparam>
public sealed class NoneSpecification<T> : Specification<T>
{
#region Public Methods
/// <summary>
/// Gets the LINQ expression which represents the current specification.
/// </summary>
/// <returns>The LINQ expression.</returns>
public override Expression<Func<T, bool>> GetExpression()
{
return o => false;
}
#endregion
}
}

View File

@@ -0,0 +1,40 @@

using System;
using System.Linq.Expressions;
namespace MyCode.Project.Infrastructure
{
/// <summary>
/// Represents the specification which indicates the semantics opposite to the given specification.
/// </summary>
/// <typeparam name="T">The type of the object to which the specification is applied.</typeparam>
public class NotSpecification<T> : Specification<T>
{
#region Private Fields
private ISpecification<T> spec;
#endregion
#region Ctor
/// <summary>
/// Initializes a new instance of <c>NotSpecification&lt;T&gt;</c> class.
/// </summary>
/// <param name="specification">The specification to be reversed.</param>
public NotSpecification(ISpecification<T> specification)
{
this.spec = specification;
}
#endregion
#region Public Methods
/// <summary>
/// Gets the LINQ expression which represents the current specification.
/// </summary>
/// <returns>The LINQ expression.</returns>
public override Expression<Func<T, bool>> GetExpression()
{
var body = Expression.Not(this.spec.GetExpression().Body);
return Expression.Lambda<Func<T, bool>>(body, this.spec.GetExpression().Parameters);
}
#endregion
}
}

View File

@@ -0,0 +1,36 @@

using System;
using System.Linq.Expressions;
namespace MyCode.Project.Infrastructure
{
/// <summary>
/// Represents the combined specification which indicates that either of the given
/// specification should be satisfied by the given object.
/// </summary>
/// <typeparam name="T">The type of the object to which the specification is applied.</typeparam>
public class OrSpecification<T> : CompositeSpecification<T>
{
#region Ctor
/// <summary>
/// Initializes a new instance of <c>OrSpecification&lt;T&gt;</c> class.
/// </summary>
/// <param name="left">The first specification.</param>
/// <param name="right">The second specification.</param>
public OrSpecification(ISpecification<T> left, ISpecification<T> right) : base(left, right) { }
#endregion
#region Public Methods
/// <summary>
/// Gets the LINQ expression which represents the current specification.
/// </summary>
/// <returns>The LINQ expression.</returns>
public override Expression<Func<T, bool>> GetExpression()
{
//var body = Expression.OrElse(Left.GetExpression().Body, Right.GetExpression().Body);
//return Expression.Lambda<Func<T, bool>>(body, Left.GetExpression().Parameters);
return Left.GetExpression().Or(Right.GetExpression());
}
#endregion
}
}

View File

@@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
namespace MyCode.Project.Infrastructure
{
/// <summary>
/// Represents the parameter rebinder used for rebinding the parameters
/// for the given expressions. This is part of the solution which solves
/// the expression parameter problem when going to Entity Framework by using
/// Apworks specifications. For more information about this solution please
/// refer to http://blogs.msdn.com/b/meek/archive/2008/05/02/linq-to-entities-combining-predicates.aspx.
/// </summary>
internal class ParameterRebinder : ExpressionVisitor
{
#region Private Fields
private readonly Dictionary<ParameterExpression, ParameterExpression> map;
#endregion
#region Ctor
internal ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map)
{
this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();
}
#endregion
#region Internal Static Methods
internal static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp)
{
return new ParameterRebinder(map).Visit(exp);
}
#endregion
#region Protected Methods
protected override Expression VisitParameter(ParameterExpression p)
{
ParameterExpression replacement;
if (map.TryGetValue(p, out replacement))
{
p = replacement;
}
return base.VisitParameter(p);
}
#endregion
}
}

View File

@@ -0,0 +1,88 @@

using System;
using System.Linq.Expressions;
namespace MyCode.Project.Infrastructure
{
/// <summary>
/// Represents the base class for specifications.
/// </summary>
/// <typeparam name="T">The type of the object to which the specification is applied.</typeparam>
public abstract class Specification<T> : ISpecification<T>
{
#region Public Methods
/// <summary>
/// Evaluates a LINQ expression to its corresponding specification.
/// </summary>
/// <param name="expression">The LINQ expression to be evaluated.</param>
/// <returns>The specification which represents the same semantics as the given LINQ expression.</returns>
public static Specification<T> Eval(Expression<Func<T, bool>> expression)
{
return new ExpressionSpecification<T>(expression);
}
#endregion
#region ISpecification<T> Members
/// <summary>
/// Returns a <see cref="System.Boolean"/> value which indicates whether the specification
/// is satisfied by the given object.
/// </summary>
/// <param name="obj">The object to which the specification is applied.</param>
/// <returns>True if the specification is satisfied, otherwise false.</returns>
public virtual bool IsSatisfiedBy(T obj)
{
return this.GetExpression().Compile()(obj);
}
/// <summary>
/// Combines the current specification instance with another specification instance
/// and returns the combined specification which represents that both the current and
/// the given specification must be satisfied by the given object.
/// </summary>
/// <param name="other">The specification instance with which the current specification
/// is combined.</param>
/// <returns>The combined specification instance.</returns>
public ISpecification<T> And(ISpecification<T> other)
{
return new AndSpecification<T>(this, other);
}
/// <summary>
/// Combines the current specification instance with another specification instance
/// and returns the combined specification which represents that either the current or
/// the given specification should be satisfied by the given object.
/// </summary>
/// <param name="other">The specification instance with which the current specification
/// is combined.</param>
/// <returns>The combined specification instance.</returns>
public ISpecification<T> Or(ISpecification<T> other)
{
return new OrSpecification<T>(this, other);
}
/// <summary>
/// Combines the current specification instance with another specification instance
/// and returns the combined specification which represents that the current specification
/// should be satisfied by the given object but the specified specification should not.
/// </summary>
/// <param name="other">The specification instance with which the current specification
/// is combined.</param>
/// <returns>The combined specification instance.</returns>
public ISpecification<T> AndNot(ISpecification<T> other)
{
return new AndNotSpecification<T>(this, other);
}
/// <summary>
/// Reverses the current specification instance and returns a specification which represents
/// the semantics opposite to the current specification.
/// </summary>
/// <returns>The reversed specification instance.</returns>
public ISpecification<T> Not()
{
return new NotSpecification<T>(this);
}
/// <summary>
/// Gets the LINQ expression which represents the current specification.
/// </summary>
/// <returns>The LINQ expression.</returns>
public abstract Expression<Func<T, bool>> GetExpression();
#endregion
}
}