Last active
April 1, 2023 05:17
-
-
Save kemsky/77c44d461356c41ff76725a53b722a35 to your computer and use it in GitHub Desktop.
Remaining bits
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static class ExpressionExtensions | |
{ | |
public static Option<object, Expression> TryEvaluate(this Expression expression) | |
{ | |
if (expression is MemberExpression memberExpression) | |
{ | |
if (memberExpression.Expression == null) | |
{ | |
if (memberExpression.Member is PropertyInfo staticProperty) | |
{ | |
return Option.Some<object, Expression>(staticProperty.GetValue(null)); | |
} | |
else if (memberExpression.Member is FieldInfo staticField) | |
{ | |
return Option.Some<object, Expression>(staticField.GetValue(null)); | |
} | |
else | |
{ | |
throw new Exception($"Not supported: {memberExpression}"); | |
} | |
} | |
var stack = new Stack<MemberExpression>(); | |
var e = memberExpression; | |
while (e != null) | |
{ | |
stack.Push(e); | |
e = e.Expression as MemberExpression; | |
} | |
if (stack.Peek().Expression is ConstantExpression constantExpression) | |
{ | |
var value = constantExpression.Value; | |
while (stack.TryPop(out var stackExpression)) | |
{ | |
if (stackExpression.Member is PropertyInfo propertyInfo) | |
{ | |
value = propertyInfo.GetValue(value); | |
} | |
else if (stackExpression.Member is FieldInfo fieldInfo) | |
{ | |
value = fieldInfo.GetValue(value); | |
} | |
else | |
{ | |
return Option.None<object, Expression>(expression); | |
} | |
} | |
return Option.Some<object, Expression>(value); | |
} | |
else | |
{ | |
return Option.None<object, Expression>(expression); | |
} | |
} | |
else if (expression is ConstantExpression constantExpression) | |
{ | |
return Option.Some<object, Expression>(constantExpression.Value); | |
} | |
return Option.None<object, Expression>(expression); | |
} | |
} | |
public class RebindParameter : ExpressionVisitor | |
{ | |
private readonly ParameterExpression _parameter; | |
private readonly Expression _replace; | |
public RebindParameter(ParameterExpression parameter, Expression replace) | |
{ | |
_parameter = parameter; | |
_replace = replace; | |
} | |
public override Expression Visit(Expression node) | |
{ | |
if (node is ParameterExpression parameterExpression && parameterExpression == _parameter) | |
{ | |
return _replace; | |
} | |
else | |
{ | |
return base.Visit(node); | |
} | |
} | |
} | |
public class ProjectionSingleVisitor : ExpressionVisitor | |
{ | |
protected override Expression VisitInvocation(InvocationExpression node) | |
{ | |
if (node.Expression is MemberExpression memberExpression) | |
{ | |
if (memberExpression.Member.DeclaringType?.IsGenericType == true && memberExpression.Member.DeclaringType.GetGenericTypeDefinition() == typeof(Projection<,>)) | |
{ | |
var projection = (IProjection)memberExpression.Expression.TryEvaluate().ValueOrFailure(); | |
var lambda = projection.GetProjectToExpression(); | |
var body = lambda.Body; | |
var rebindParameter = new RebindParameter(lambda.Parameters[0], node.Arguments[0]); | |
var expression = rebindParameter.Visit(body); | |
if (expression.Type.IsClass || Nullable.GetUnderlyingType(expression.Type) != null) | |
{ | |
var checkNullExpression = Expression.Equal(node.Arguments[0], Expression.Constant(null, node.Arguments[0].Type)); | |
var nullExpression = Expression.Constant(null, expression.Type); | |
var conditional = Expression.Condition(checkNullExpression, nullExpression, expression); | |
return base.Visit(conditional); | |
} | |
else | |
{ | |
return base.Visit(expression); | |
} | |
} | |
} | |
return base.VisitInvocation(node); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi!
Please, can you tell me what is the type Option<,>? It is from some functional lib for c#?