发布x.3.1.60修复默认读写分离全局设置不起效

This commit is contained in:
xuejiaming 2021-12-02 12:22:32 +08:00
parent 028d3b08cb
commit 2bae992d2c
6 changed files with 506 additions and 0 deletions

View File

@ -0,0 +1,13 @@
using System.Collections.Generic;
using System.Linq.Expressions;
using ShardingCore.Core.ExtensionExpressionComparer.Internals;
namespace ShardingCore.Core.ExtensionExpressionComparer
{
public class ExpressionEqualityComparer : IEqualityComparer<Expression>
{
public bool Equals(Expression x, Expression y) => new ExpressionValueComparer().Compare(x, y);
public int GetHashCode(Expression obj) => new ExpressionHashCodeResolver().GetHashCodeFor(obj);
}
}

View File

@ -0,0 +1,67 @@
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
namespace ShardingCore.Core.ExtensionExpressionComparer.Internals
{
class ConstantValue
{
public object Value { get; }
public static bool IsConstantValue(Expression e)
{
switch (e)
{
case ConstantExpression constant: return true;
case MemberExpression me: return me.Expression == null || IsConstantValue(me.Expression);
case NewArrayExpression ae: return ae.Expressions.All(IsConstantValue);
case ConditionalExpression ce:
var evaluatedTest = New(ce.Test);
if (evaluatedTest != null)
{
return IsConstantValue(Equals(evaluatedTest.Value, true) ? ce.IfTrue : ce.IfFalse);
}
break;
}
return false;
}
public static ConstantValue New(Expression e)
{
var isConstant = IsConstantValue(e);
if (!isConstant)
{
return null;
}
switch (e)
{
case ConstantExpression constant: return new ConstantValue(constant.Value);
case MemberExpression me:
if (me.Member is FieldInfo fieldInfo)
{
return new ConstantValue(fieldInfo.GetValue(me.Expression == null ? null : New(me.Expression).Value));
}
if (me.Member is PropertyInfo propertyInfo)
{
return new ConstantValue(propertyInfo.GetValue(me.Expression == null ? null : New(me.Expression).Value));
}
break;
case NewArrayExpression ae: return new ConstantValue(ae.Expressions.Select(i => New(i).Value).ToArray());
case ConditionalExpression ce: return New(Equals(New(ce.Test).Value, true) ? ce.IfTrue : ce.IfFalse);
}
return default;
}
public ConstantValue(object value)
{
Value = value;
}
}
}

View File

@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace ShardingCore.Core.ExtensionExpressionComparer.Internals
{
static class ExpressionExtensions
{
public static bool IsEqualTo<TExpression, TMember>(this TExpression value, TExpression other, Func<TExpression, TMember> reader)
{
return EqualityComparer<TMember>.Default.Equals(reader.Invoke(value), reader.Invoke(other));
}
public static bool IsEqualTo<TExpression>(this TExpression value, TExpression other, params Func<TExpression, object>[] reader)
{
return reader.All(_ => EqualityComparer<object>.Default.Equals(_.Invoke(value), _.Invoke(other)));
}
public static int GetHashCodeFor<TExpression, TProperty>(this TExpression value, TProperty prop)
{
unchecked
{
var hash = 17;
hash = hash * 23 + prop.GetHashCode();
return hash;
}
}
public static int GetHashCodeFor<TExpression>(this TExpression value, params object[] props)
{
unchecked
{
return props.Where(prop => prop != null).Aggregate(17, (current, prop) => current * 23 + prop.GetHashCode());
}
}
}
}

View File

@ -0,0 +1,44 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Linq.Expressions;
namespace ShardingCore.Core.ExtensionExpressionComparer.Internals
{
class ExpressionFlattener : ExpressionVisitor
{
private List<Expression> _result;
public List<Expression> Flatten(Expression expression)
{
_result = new List<Expression>();
Visit(expression);
return _result;
}
public override Expression Visit(Expression node)
{
//conversion to constant if possible
var constantValue = ConstantValue.New(node);
if (constantValue != null)
{
_result.Add(Expression.Constant(constantValue.Value));
return node;
}
else
{
_result.Add(node);
return base.Visit(node);
}
}
protected override Expression VisitMemberInit(MemberInitExpression node)
{
//explicit ordering
return node.Update(
VisitAndConvert(node.NewExpression, nameof(VisitMemberInit)),
Visit(new ReadOnlyCollection<MemberBinding>(node.Bindings.OrderBy(b => b.Member.Name).ToList()), VisitMemberBinding)
);
}
}
}

View File

@ -0,0 +1,149 @@
using System.Linq.Expressions;
namespace ShardingCore.Core.ExtensionExpressionComparer.Internals
{
class ExpressionHashCodeResolver : ExpressionVisitor
{
private int _result;
public int GetHashCodeFor(Expression obj)
{
_result = 0;
Visit(obj);
return _result;
}
public override Expression Visit(Expression node)
{
if (null == node) return null;
_result += node.GetHashCodeFor(node.NodeType, node.Type);
return base.Visit(node);
}
protected override Expression VisitBinary(BinaryExpression node)
{
_result += node.GetHashCodeFor(node.Method, node.IsLifted, node.IsLiftedToNull);
return base.VisitBinary(node);
}
protected override CatchBlock VisitCatchBlock(CatchBlock node)
{
_result += node.GetHashCodeFor(node.Test);
return base.VisitCatchBlock(node);
}
protected override Expression VisitConstant(ConstantExpression node)
{
_result += node.GetHashCodeFor(node.Value);
return base.VisitConstant(node);
}
protected override Expression VisitDebugInfo(DebugInfoExpression node)
{
_result += node.GetHashCodeFor(node.Document, node.EndColumn, node.EndLine, node.IsClear, node.StartLine, node.StartColumn);
return base.VisitDebugInfo(node);
}
protected override Expression VisitDynamic(DynamicExpression node)
{
_result += node.GetHashCodeFor(node.DelegateType, node.Binder);
return base.VisitDynamic(node);
}
protected override ElementInit VisitElementInit(ElementInit node)
{
_result += node.GetHashCodeFor(node.AddMethod);
return base.VisitElementInit(node);
}
protected override Expression VisitGoto(GotoExpression node)
{
_result += node.GetHashCodeFor(node.Kind, node.Target);
return base.VisitGoto(node);
}
protected override Expression VisitIndex(IndexExpression node)
{
_result += node.GetHashCodeFor(node.Indexer);
return base.VisitIndex(node);
}
protected override LabelTarget VisitLabelTarget(LabelTarget node)
{
_result += node.GetHashCodeFor(node.Name, node.Type);
return base.VisitLabelTarget(node);
}
protected override Expression VisitLambda<T>(Expression<T> node)
{
_result += node.GetHashCodeFor(node.Name, node.TailCall);
return base.VisitLambda(node);
}
protected override Expression VisitListInit(ListInitExpression node)
{
_result += node.GetHashCodeFor(node.Initializers);
return base.VisitListInit(node);
}
protected override Expression VisitLoop(LoopExpression node)
{
_result += node.GetHashCodeFor(node.BreakLabel, node.ContinueLabel);
return base.VisitLoop(node);
}
protected override Expression VisitMember(MemberExpression node)
{
_result += node.GetHashCodeFor(node.Member);
return base.VisitMember(node);
}
protected override MemberBinding VisitMemberBinding(MemberBinding node)
{
_result += node.GetHashCodeFor(node.BindingType, node.Member);
return base.VisitMemberBinding(node);
}
protected override Expression VisitMethodCall(MethodCallExpression node)
{
_result += node.GetHashCodeFor(node.Method);
return base.VisitMethodCall(node);
}
protected override Expression VisitNew(NewExpression node)
{
_result += node.GetHashCodeFor(node.Constructor, node.Members);
return base.VisitNew(node);
}
protected override Expression VisitParameter(ParameterExpression node)
{
_result += node.GetHashCodeFor(node.IsByRef);
return base.VisitParameter(node);
}
protected override Expression VisitSwitch(SwitchExpression node)
{
_result += node.GetHashCodeFor(node.Comparison);
return base.VisitSwitch(node);
}
protected override Expression VisitTry(TryExpression node)
{
_result += node.GetHashCodeFor(node.Handlers);
return base.VisitTry(node);
}
protected override Expression VisitTypeBinary(TypeBinaryExpression node)
{
_result += node.GetHashCodeFor(node.TypeOperand);
return base.VisitTypeBinary(node);
}
protected override Expression VisitUnary(UnaryExpression node)
{
_result += node.GetHashCodeFor(node.Method, node.IsLifted, node.IsLiftedToNull);
return base.VisitUnary(node);
}
}
}

View File

@ -0,0 +1,196 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Linq.Expressions;
namespace ShardingCore.Core.ExtensionExpressionComparer.Internals
{
//inspired by
//https://github.com/yuriy-nelipovich/LambdaCompare/blob/master/Neleus.LambdaCompare/Comparer.cs
//https://github.com/yesmarket/yesmarket.Linq.Expressions/blob/master/yesmarket.Linq.Expressions/Support/ExpressionValueComparer.cs
sealed class ExpressionValueComparer : ExpressionVisitor
{
private Queue<Expression> _tracked;
private Expression _current;
private bool _eq;
public bool Compare(Expression x, Expression y)
{
_tracked = new Queue<Expression>(new ExpressionFlattener().Flatten(y));
_current = null;
_eq = true;
Visit(x);
return _eq;
}
public override Expression Visit(Expression node)
{
if (!_eq)
{
return node;
}
if (_tracked.Count == 0)
{
_eq = false;
return node;
}
_current = _tracked.Dequeue();
if (_current == null && node == null)
{
return base.Visit(node);
}
var testedNode = node;
var constantValue = ConstantValue.New(node);
if (constantValue != null)
{
testedNode = Expression.Constant(constantValue.Value);
}
if (_current == null || testedNode == null || _current.NodeType != testedNode.NodeType || !(_current.Type.IsAssignableFrom(testedNode.Type) || testedNode.Type.IsAssignableFrom(_current.Type)))
{
_eq = false;
return node;
}
return base.Visit(testedNode);
}
protected override Expression VisitBinary(BinaryExpression node)
{
var other = (BinaryExpression)_current;
_eq &= node.IsEqualTo(other, _ => _.Method, _ => _.IsLifted, _ => _.IsLiftedToNull);
return _eq ? base.VisitBinary(node) : node;
}
protected override Expression VisitConstant(ConstantExpression node)
{
var other = (ConstantExpression)_current;
_eq &= node.IsEqualTo(other, _ => _.Value);
return _eq ? base.VisitConstant(node) : node;
}
protected override Expression VisitDebugInfo(DebugInfoExpression node)
{
var other = (DebugInfoExpression)_current;
_eq &= node.IsEqualTo(other, _ => _.EndColumn, _ => _.EndLine, _ => _.IsClear, _ => _.StartLine, _ => _.StartColumn);
return _eq ? base.VisitDebugInfo(node) : node;
}
protected override Expression VisitDynamic(DynamicExpression node)
{
var other = (DynamicExpression)_current;
_eq &= node.IsEqualTo(other, _ => _.DelegateType, _ => _.Binder);
return _eq ? base.VisitDynamic(node) : node;
}
protected override Expression VisitGoto(GotoExpression node)
{
var other = (GotoExpression)_current;
_eq &= node.IsEqualTo(other, _ => _.Kind, _ => _.Target);
return _eq ? base.VisitGoto(node) : node;
}
protected override Expression VisitIndex(IndexExpression node)
{
var other = (IndexExpression)_current;
_eq &= node.IsEqualTo(other, _ => _.Indexer);
return _eq ? base.VisitIndex(node) : node;
}
protected override Expression VisitLabel(LabelExpression node)
{
var other = (LabelExpression)_current;
_eq &= node.IsEqualTo(other, _ => _.Target);
return _eq ? base.VisitLabel(node) : node;
}
protected override Expression VisitLambda<T>(Expression<T> node)
{
var other = (LambdaExpression)_current;
_eq &= node.IsEqualTo(other, _ => _.Name, _ => _.TailCall);
return _eq ? base.VisitLambda(node) : node;
}
protected override Expression VisitListInit(ListInitExpression node)
{
var other = (ListInitExpression)_current;
_eq &= node.IsEqualTo(other, _ => _.Initializers);
return _eq ? base.VisitListInit(node) : node;
}
protected override Expression VisitLoop(LoopExpression node)
{
var other = (LoopExpression)_current;
_eq &= node.IsEqualTo(other, _ => _.BreakLabel, _ => _.ContinueLabel);
return _eq ? base.VisitLoop(node) : node;
}
protected override Expression VisitMember(MemberExpression node)
{
var other = (MemberExpression)_current;
_eq &= node.IsEqualTo(other, _ => _.Member);
return _eq ? base.VisitMember(node) : node;
}
protected override Expression VisitMemberInit(MemberInitExpression node)
{
if (_eq)
{
return node.Update(
VisitAndConvert(node.NewExpression, nameof(VisitMemberInit)),
Visit(new ReadOnlyCollection<MemberBinding>(node.Bindings.OrderBy(b => b.Member.Name).ToList()), VisitMemberBinding)
);
}
return node;
}
protected override Expression VisitMethodCall(MethodCallExpression node)
{
var other = (MethodCallExpression)_current;
_eq &= node.IsEqualTo(other, _ => _.Method);
return _eq ? base.VisitMethodCall(node) : node;
}
protected override Expression VisitNew(NewExpression node)
{
var other = (NewExpression)_current;
_eq &= node.IsEqualTo(other, _ => _.Constructor, _ => _.Members);
return _eq ? base.VisitNew(node) : node;
}
protected override Expression VisitSwitch(SwitchExpression node)
{
var other = (SwitchExpression)_current;
_eq &= node.IsEqualTo(other, _ => _.Comparison);
return _eq ? base.VisitSwitch(node) : node;
}
protected override Expression VisitTry(TryExpression node)
{
var other = (TryExpression)_current;
_eq &= node.IsEqualTo(other, _ => _.Handlers);
return _eq ? base.VisitTry(node) : node;
}
protected override Expression VisitTypeBinary(TypeBinaryExpression node)
{
var other = (TypeBinaryExpression)_current;
_eq &= node.IsEqualTo(other, _ => _.TypeOperand);
return _eq ? base.VisitTypeBinary(node) : node;
}
protected override Expression VisitUnary(UnaryExpression node)
{
var other = (UnaryExpression)_current;
_eq &= node.IsEqualTo(other, _ => _.Method, _ => _.IsLifted, _ => _.IsLiftedToNull);
return _eq ? base.VisitUnary(node) : node;
}
}
}