现在的位置: 首页 > 综合 > 正文

MVC+LINQToSQL的Repository模式之(四)数据统一更新的附加类

2012年09月11日 ⁄ 综合 ⁄ 共 18531字 ⁄ 字号 评论关闭
namespace System.Linq.Dynamic
{
public static class DynamicQueryable
{
public static IQueryable<T> Where<T>(this IQueryable<T> source, string predicate, params object[] values) {
return (IQueryable<T>)Where((IQueryable)source, predicate, values);
}

public static IQueryable Where(this IQueryable source, string predicate, params object[] values) {
if (source == null) throw new ArgumentNullException("source");
if (predicate == null) throw new ArgumentNullException("predicate");
LambdaExpression lambda = DynamicExpression.ParseLambda(source.ElementType, typeof(bool), predicate, values);
return source.Provider.CreateQuery(
Expression.Call(
typeof(Queryable), "Where",
new Type[] { source.ElementType },
source.Expression, Expression.Quote(lambda)));
}

public static IQueryable Select(this IQueryable source, string selector, params object[] values) {
if (source == null) throw new ArgumentNullException("source");
if (selector == null) throw new ArgumentNullException("selector");
LambdaExpression lambda = DynamicExpression.ParseLambda(source.ElementType, null, selector, values);
return source.Provider.CreateQuery(
Expression.Call(
typeof(Queryable), "Select",
new Type[] { source.ElementType, lambda.Body.Type },
source.Expression, Expression.Quote(lambda)));
}

public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, string ordering, params object[] values) {
return (IQueryable<T>)OrderBy((IQueryable)source, ordering, values);
}

public static IQueryable OrderBy(this IQueryable source, string ordering, params object[] values) {
if (source == null) throw new ArgumentNullException("source");
if (ordering == null) throw new ArgumentNullException("ordering");
ParameterExpression[] parameters = new ParameterExpression[] {
Expression.Parameter(source.ElementType, "") };
ExpressionParser parser = new ExpressionParser(parameters, ordering, values);
IEnumerable<DynamicOrdering> orderings = parser.ParseOrdering();
Expression queryExpr = source.Expression;
string methodAsc = "OrderBy";
string methodDesc = "OrderByDescending";
foreach (DynamicOrdering o in orderings) {
queryExpr = Expression.Call(
typeof(Queryable), o.Ascending ? methodAsc : methodDesc,
new Type[] { source.ElementType, o.Selector.Type },
queryExpr, Expression.Quote(Expression.Lambda(o.Selector, parameters)));
methodAsc = "ThenBy";
methodDesc = "ThenByDescending";
}
return source.Provider.CreateQuery(queryExpr);
}

public static IQueryable Take(this IQueryable source, int count) {
if (source == null) throw new ArgumentNullException("source");
return source.Provider.CreateQuery(
Expression.Call(
typeof(Queryable), "Take",
new Type[] { source.ElementType },
source.Expression, Expression.Constant(count)));
}

public static IQueryable Skip(this IQueryable source, int count) {
if (source == null) throw new ArgumentNullException("source");
return source.Provider.CreateQuery(
Expression.Call(
typeof(Queryable), "Skip",
new Type[] { source.ElementType },
source.Expression, Expression.Constant(count)));
}

public static IQueryable GroupBy(this IQueryable source, string keySelector, string elementSelector, params object[] values) {
if (source == null) throw new ArgumentNullException("source");
if (keySelector == null) throw new ArgumentNullException("keySelector");
if (elementSelector == null) throw new ArgumentNullException("elementSelector");
LambdaExpression keyLambda = DynamicExpression.ParseLambda(source.ElementType, null, keySelector, values);
LambdaExpression elementLambda = DynamicExpression.ParseLambda(source.ElementType, null, elementSelector, values);
return source.Provider.CreateQuery(
Expression.Call(
typeof(Queryable), "GroupBy",
new Type[] { source.ElementType, keyLambda.Body.Type, elementLambda.Body.Type },
source.Expression, Expression.Quote(keyLambda), Expression.Quote(elementLambda)));
}

public static bool Any(this IQueryable source) {
if (source == null) throw new ArgumentNullException("source");
return (bool)source.Provider.Execute(
Expression.Call(
typeof(Queryable), "Any",
new Type[] { source.ElementType }, source.Expression));
}

public static int Count(this IQueryable source) {
if (source == null) throw new ArgumentNullException("source");
return (int)source.Provider.Execute(
Expression.Call(
typeof(Queryable), "Count",
new Type[] { source.ElementType }, source.Expression));
}
}

public abstract class DynamicClass
{
public override string ToString() {
PropertyInfo[] props = this.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);
StringBuilder sb = new StringBuilder();
sb.Append("{");
for (int i = 0; i < props.Length; i++) {
if (i > 0) sb.Append(", ");
sb.Append(props[i].Name);
sb.Append("=");
sb.Append(props[i].GetValue(this, null));
}
sb.Append("}");
return sb.ToString();
}
}

public class DynamicProperty
{
string name;
Type type;

public DynamicProperty(string name, Type type) {
if (name == null) throw new ArgumentNullException("name");
if (type == null) throw new ArgumentNullException("type");
this.name = name;
this.type = type;
}

public string Name {
get { return name; }
}

public Type Type {
get { return type; }
}
}

public static class DynamicExpression
{
public static Expression Parse(Type resultType, string expression, params object[] values) {
ExpressionParser parser = new ExpressionParser(null, expression, values);
return parser.Parse(resultType);
}

public static LambdaExpression ParseLambda(Type itType, Type resultType, string expression, params object[] values) {
return ParseLambda(new ParameterExpression[] { Expression.Parameter(itType, "") }, resultType, expression, values);
}

public static LambdaExpression ParseLambda(ParameterExpression[] parameters, Type resultType, string expression, params object[] values) {
ExpressionParser parser = new ExpressionParser(parameters, expression, values);
return Expression.Lambda(parser.Parse(resultType), parameters);
}

public static Expression<Func<T, S>> ParseLambda<T, S>(string expression, params object[] values) {
return (Expression<Func<T, S>>)ParseLambda(typeof(T), typeof(S), expression, values);
}

public static Type CreateClass(params DynamicProperty[] properties) {
return ClassFactory.Instance.GetDynamicClass(properties);
}

public static Type CreateClass(IEnumerable<DynamicProperty> properties) {
return ClassFactory.Instance.GetDynamicClass(properties);
}
}

internal class DynamicOrdering
{
public Expression Selector;
public bool Ascending;
}

internal class Signature : IEquatable<Signature>
{
public DynamicProperty[] properties;
public int hashCode;

public Signature(IEnumerable<DynamicProperty> properties) {
this.properties = properties.ToArray();
hashCode = 0;
foreach (DynamicProperty p in properties) {
hashCode ^= p.Name.GetHashCode() ^ p.Type.GetHashCode();
}
}

public override int GetHashCode() {
return hashCode;
}

public override bool Equals(object obj) {
return obj is Signature ? Equals((Signature)obj) : false;
}

public bool Equals(Signature other) {
if (properties.Length != other.properties.Length) return false;
for (int i = 0; i < properties.Length; i++) {
if (properties[i].Name != other.properties[i].Name ||
properties[i].Type != other.properties[i].Type) return false;
}
return true;
}
}

internal class ClassFactory
{
public static readonly ClassFactory Instance = new ClassFactory();

static ClassFactory() { } // Trigger lazy initialization of static fields

ModuleBuilder module;
Dictionary<Signature, Type> classes;
int classCount;
ReaderWriterLock rwLock;

private ClassFactory() {
AssemblyName name = new AssemblyName("DynamicClasses");
AssemblyBuilder assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run);
#if ENABLE_LINQ_PARTIAL_TRUST
new ReflectionPermission(PermissionState.Unrestricted).Assert();
#endif
try
{
module = assembly.DefineDynamicModule("Module");
}
finally {
#if ENABLE_LINQ_PARTIAL_TRUST
PermissionSet.RevertAssert();
#endif
}
classes = new Dictionary<Signature, Type>();
rwLock = new ReaderWriterLock();
}

public Type GetDynamicClass(IEnumerable<DynamicProperty> properties) {
rwLock.AcquireReaderLock(Timeout.Infinite);
try {
Signature signature = new Signature(properties);
Type type;
if (!classes.TryGetValue(signature, out type)) {
type = CreateDynamicClass(signature.properties);
classes.Add(signature, type);
}
return type;
}
finally {
rwLock.ReleaseReaderLock();
}
}

Type CreateDynamicClass(DynamicProperty[] properties) {
LockCookie cookie = rwLock.UpgradeToWriterLock(Timeout.Infinite);
try {
string typeName = "DynamicClass" + (classCount + 1);
#if ENABLE_LINQ_PARTIAL_TRUST
new ReflectionPermission(PermissionState.Unrestricted).Assert();
#endif
try
{
TypeBuilder tb = this.module.DefineType(typeName, TypeAttributes.Class |
TypeAttributes.Public, typeof(DynamicClass));
FieldInfo[] fields = GenerateProperties(tb, properties);
GenerateEquals(tb, fields);
GenerateGetHashCode(tb, fields);
Type result = tb.CreateType();
classCount++;
return result;
}
finally {
#if ENABLE_LINQ_PARTIAL_TRUST
PermissionSet.RevertAssert();
#endif
}
}
finally {
rwLock.DowngradeFromWriterLock(ref cookie);
}
}

FieldInfo[] GenerateProperties(TypeBuilder tb, DynamicProperty[] properties) {
FieldInfo[] fields = new FieldBuilder[properties.Length];
for (int i = 0; i < properties.Length; i++) {
DynamicProperty dp = properties[i];
FieldBuilder fb = tb.DefineField("_" + dp.Name, dp.Type, FieldAttributes.Private);
PropertyBuilder pb = tb.DefineProperty(dp.Name, PropertyAttributes.HasDefault, dp.Type, null);
MethodBuilder mbGet = tb.DefineMethod("get_" + dp.Name,
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
dp.Type, Type.EmptyTypes);
ILGenerator genGet = mbGet.GetILGenerator();
genGet.Emit(OpCodes.Ldarg_0);
genGet.Emit(OpCodes.Ldfld, fb);
genGet.Emit(OpCodes.Ret);
MethodBuilder mbSet = tb.DefineMethod("set_" + dp.Name,
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
null, new Type[] { dp.Type });
ILGenerator genSet = mbSet.GetILGenerator();
genSet.Emit(OpCodes.Ldarg_0);
genSet.Emit(OpCodes.Ldarg_1);
genSet.Emit(OpCodes.Stfld, fb);
genSet.Emit(OpCodes.Ret);
pb.SetGetMethod(mbGet);
pb.SetSetMethod(mbSet);
fields[i] = fb;
}
return fields;
}

void GenerateEquals(TypeBuilder tb, FieldInfo[] fields) {
MethodBuilder mb = tb.DefineMethod("Equals",
MethodAttributes.Public | MethodAttributes.ReuseSlot |
MethodAttributes.Virtual | MethodAttributes.HideBySig,
typeof(bool), new Type[] { typeof(object) });
ILGenerator gen = mb.GetILGenerator();
LocalBuilder other = gen.DeclareLocal(tb);
Label next = gen.DefineLabel();
gen.Emit(OpCodes.Ldarg_1);
gen.Emit(OpCodes.Isinst, tb);
gen.Emit(OpCodes.Stloc, other);
gen.Emit(OpCodes.Ldloc, other);
gen.Emit(OpCodes.Brtrue_S, next);
gen.Emit(OpCodes.Ldc_I4_0);
gen.Emit(OpCodes.Ret);
gen.MarkLabel(next);
foreach (FieldInfo field in fields) {
Type ft = field.FieldType;
Type ct = typeof(EqualityComparer<>).MakeGenericType(ft);
next = gen.DefineLabel();
gen.EmitCall(OpCodes.Call, ct.GetMethod("get_Default"), null);
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldfld, field);
gen.Emit(OpCodes.Ldloc, other);
gen.Emit(OpCodes.Ldfld, field);
gen.EmitCall(OpCodes.Callvirt, ct.GetMethod("Equals", new Type[] { ft, ft }), null);
gen.Emit(OpCodes.Brtrue_S, next);
gen.Emit(OpCodes.Ldc_I4_0);
gen.Emit(OpCodes.Ret);
gen.MarkLabel(next);
}
gen.Emit(OpCodes.Ldc_I4_1);
gen.Emit(OpCodes.Ret);
}

void GenerateGetHashCode(TypeBuilder tb, FieldInfo[] fields) {
MethodBuilder mb = tb.DefineMethod("GetHashCode",
MethodAttributes.Public | MethodAttributes.ReuseSlot |
MethodAttributes.Virtual | MethodAttributes.HideBySig,
typeof(int), Type.EmptyTypes);
ILGenerator gen = mb.GetILGenerator();
gen.Emit(OpCodes.Ldc_I4_0);
foreach (FieldInfo field in fields) {
Type ft = field.FieldType;
Type ct = typeof(EqualityComparer<>).MakeGenericType(ft);
gen.EmitCall(OpCodes.Call, ct.GetMethod("get_Default"), null);
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldfld, field);
gen.EmitCall(OpCodes.Callvirt, ct.GetMethod("GetHashCode", new Type[] { ft }), null);
gen.Emit(OpCodes.Xor);
}
gen.Emit(OpCodes.Ret);
}
}

public sealed class ParseException : Exception
{
int position;

public ParseException(string message, int position)
: base(message) {
this.position = position;
}

public int Position {
get { return position; }
}

public override string ToString() {
return string.Format(Res.ParseExceptionFormat, Message, position);
}
}

internal class ExpressionParser
{
struct Token
{
public TokenId id;
public string text;
public int pos;
}

enum TokenId
{
Unknown,
End,
Identifier,
StringLiteral,
IntegerLiteral,
RealLiteral,
Exclamation,
Percent,
Amphersand,
OpenParen,
CloseParen,
Asterisk,
Plus,
Comma,
Minus,
Dot,
Slash,
Colon,
LessThan,
Equal,
GreaterThan,
Question,
OpenBracket,
CloseBracket,
Bar,
ExclamationEqual,
DoubleAmphersand,
LessThanEqual,
LessGreater,
DoubleEqual,
GreaterThanEqual,
DoubleBar
}

interface ILogicalSignatures
{
void F(bool x, bool y);
void F(bool? x, bool? y);
}

interface IArithmeticSignatures
{
void F(int x, int y);
void F(uint x, uint y);
void F(long x, long y);
void F(ulong x, ulong y);
void F(float x, float y);
void F(double x, double y);
void F(decimal x, decimal y);
void F(int? x, int? y);
void F(uint? x, uint? y);
void F(long? x, long? y);
void F(ulong? x, ulong? y);
void F(float? x, float? y);
void F(double? x, double? y);
void F(decimal? x, decimal? y);
}

interface IRelationalSignatures : IArithmeticSignatures
{
void F(string x, string y);
void F(char x, char y);
void F(DateTime x, DateTime y);
void F(TimeSpan x, TimeSpan y);
void F(char? x, char? y);
void F(DateTime? x, DateTime? y);
void F(TimeSpan? x, TimeSpan? y);
}

interface IEqualitySignatures : IRelationalSignatures
{
void F(bool x, bool y);
void F(bool? x, bool? y);
}

interface IAddSignatures : IArithmeticSignatures
{
void F(DateTime x, TimeSpan y);
void F(TimeSpan x, TimeSpan y);
void F(DateTime? x, TimeSpan? y);
void F(TimeSpan? x, TimeSpan? y);
}

interface ISubtractSignatures : IAddSignatures
{
void F(DateTime x, DateTime y);
void F(DateTime? x, DateTime? y);
}

interface INegationSignatures
{
void F(int x);
void F(long x);
void F(float x);
void F(double x);
void F(decimal x);
void F(int? x);
void F(long? x);
void F(float? x);
void F(double? x);
void F(decimal? x);
}

interface INotSignatures
{
void F(bool x);
void F(bool? x);
}

interface IEnumerableSignatures
{
void Where(bool predicate);
void Any();
void Any(bool predicate);
void All(bool predicate);
void Count();
void Count(bool predicate);
void Min(object selector);
void Max(object selector);
void Sum(int selector);
void Sum(int? selector);
void Sum(long selector);
void Sum(long? selector);
void Sum(float selector);
void Sum(float? selector);
void Sum(double selector);
void Sum(double? selector);
void Sum(decimal selector);
void Sum(decimal? selector);
void Average(int selector);
void Average(int? selector);
void Average(long selector);
void Average(long? selector);
void Average(float selector);
void Average(float? selector);
void Average(double selector);
void Average(double? selector);
void Average(decimal selector);
void Average(decimal? selector);
}

static readonly Type[] predefinedTypes = {
typeof(Object),
typeof(Boolean),
typeof(Char),
typeof(String),
typeof(SByte),
typeof(Byte),
typeof(Int16),
typeof(UInt16),
typeof(Int32),
typeof(UInt32),
typeof(Int64),
typeof(UInt64),
typeof(Single),
typeof(Double),
typeof(Decimal),
typeof(DateTime),
typeof(TimeSpan),
typeof(Guid),
typeof(Math),
typeof(Convert)
};

static readonly Expression trueLiteral = Expression.Constant(true);
static readonly Expression falseLiteral = Expression.Constant(false);
static readonly Expression nullLiteral = Expression.Constant(null);

static readonly string keywordIt = "it";
static readonly string keywordIif = "iif";
static readonly string keywordNew = "new";

static Dictionary<string, object> keywords;

Dictionary<string, object> symbols;
IDictionary<string, object> externals;
Dictionary<Expression, string> literals;
ParameterExpression it;
string text;
int textPos;
int textLen;
char ch;
Token token;

public ExpressionParser(ParameterExpression[] parameters, string expression, object[] values) {
if (expression == null) throw new ArgumentNullException("expression");
if (keywords == null) keywords = CreateKeywords();
symbols = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
literals = new Dictionary<Expression, string>();
if (parameters != null) ProcessParameters(parameters);
if (values != null) ProcessValues(values);
text = expression;
textLen = text.Length;
SetTextPos(0);
NextToken();
}

void ProcessParameters(ParameterExpression[] parameters) {
foreach (ParameterExpression pe in parameters)
if (!String.IsNullOrEmpty(pe.Name))
AddSymbol(pe.Name, pe);
if (parameters.Length == 1 && String.IsNullOrEmpty(parameters[0].Name))
it = parameters[0];
}

void ProcessValues(object[] values) {
for (int i = 0; i < values.Length; i++) {
object value = values[i];
if (i == values.Length - 1 && value is IDictionary<string, object>) {
externals = (IDictionary<string, object>)value;
}
else {
AddSymbol("@" + i.ToString(System.Globalization.CultureInfo.InvariantCulture), value);
}
}
}

void AddSymbol(string name, object value) {
if (symbols.ContainsKey(name))
throw ParseError(Res.DuplicateIdentifier, name);
symbols.Add(name, value);
}

public Expression Parse(Type resultType) {
int exprPos = token.pos;
Expression expr = ParseExpression();
if (resultType != null)
if ((expr = PromoteExpression(expr, resultType, true)) == null)
throw ParseError(exprPos, Res.ExpressionTypeMismatch, GetTypeName(resultType));
ValidateToken(TokenId.End, Res.SyntaxError);
return expr;
}

#pragma warning disable 0219
public IEnumerable<DynamicOrdering> ParseOrdering() {
List<DynamicOrdering> orderings = new List<DynamicOrdering>();
while (true) {
Expression expr = ParseExpression();
bool ascending = true;
if (TokenIdentifierIs("asc") || TokenIdentifierIs("ascending")) {
NextToken();
}
else if (TokenIdentifierIs("desc") || TokenIdentifierIs("descending")) {
NextToken();
ascending = false;
}
orderings.Add(new DynamicOrdering { Selector = expr, Ascending = ascending });
if (token.id != TokenId.Comma) break;
NextToken();
}
ValidateToken(TokenId.End, Res.SyntaxError);
return orderings;
}
#pragma warning restore 0219

// ?: operator
Expression ParseExpression() {
int errorPos = token.pos;
Expression expr = ParseLogicalOr();
if (token.id == TokenId.Question) {
NextToken();
Expression expr1 = ParseExpression();
ValidateToken(TokenId.Colon, Res.ColonExpected);
NextToken();
Expression expr2 = ParseExpression();
expr = GenerateConditional(expr, expr1, expr2, errorPos);
}
return expr;
}

// ||, or operator
Expression ParseLogicalOr() {
Expression left = ParseLogicalAnd();
while (token.id == TokenId.DoubleBar || TokenIdentifierIs("or")) {
Token op = token;
NextToken();
Expression right = ParseLogicalAnd();
CheckAndPromoteOperands(typeof(ILogicalSignatures), op.text, ref left, ref right, op.pos);
left = Expression.OrElse(left, right);
}
return left;
}

// &&, and operator
Expression ParseLogicalAnd() {
Expression left = ParseComparison();
while (token.id == TokenId.DoubleAmphersand || TokenIdentifierIs("and")) {
Token op = token;
NextToken();
Expression right = ParseComparison();
CheckAndPromoteOperands(typeof(ILogicalSignatures), op.text, ref left, ref right, op.pos);
left = Expression.AndAlso(left, right);
}
return left;
}

// =, ==, !=, <>, >, >=, <, <= operators
Expression ParseComparison() {
Expression left = ParseAdditive();
while (token.id == TokenId.Equal || token.id == TokenId.DoubleEqual ||
token.id == TokenId.ExclamationEqual || token.id == TokenId.LessGreater ||
token.id == TokenId.GreaterThan || token.id == TokenId.GreaterThanEqual ||
token.id == TokenId.LessThan || token.id == TokenId.LessThanEqual) {
Token op = token;
NextToken();
Expression right = ParseAdditive();
bool isEquality = op.id == TokenId.Equal || op.id == TokenId.DoubleEqual ||
op.id == TokenId.ExclamationEqual || op.id == TokenId.LessGreater;
if (isEquality && !left.Type.IsValueType && !right.Type.IsValueType) {
if (left.Type != right.Type) {
if (left.Type.IsAssignableFrom(right.Type)) {
right = Expression.Convert(right, left.Type);
}
else if (right.Type.IsAssignableFrom(left.Type)) {
left = Expression.Convert(left, right.Type);
}
else {
throw IncompatibleOperandsError(op.text, left, right, op.pos);
}
}
}
else if (IsEnumType(left.Type) || IsEnumType(right.Type)) {
if (left.Type != right.Type) {
Expression e;
if ((e = PromoteExpression(right, left.Type, true)) != null) {
right = e;
}
else if ((e = PromoteExpression(left, right.Type, true)) != null) {
left = e;
}
else {
throw IncompatibleOperandsError(op.text, left, right, op.pos);
}
}
}
else {
CheckAndPromoteOperands(isEquality ?

抱歉!评论已关闭.