I have defined an Expression<Func<TSource, T>>
whose return type (T
) is an enum
. I am using this and other similar expressions for projecting and filtering items with entity framework.
I would also like to be able to use this expression within a context where only numeric values are expected and in that case pass / convert the expression as Expression<Func<TSource, T>>
where T
is of type int?
.
What I have tried
This post shows how to use the Visitor pattern to change the return type between object
and a reference type which works fine. It does however not work when trying the same thing with value types.
public class ReturnTypeVisitor<TSource, TReturnValue> : ExpressionVisitor
{
protected override Expression VisitLambda<T>(Expression<T> node)
{
var delegateType = typeof(Func<,>).MakeGenericType(typeof(TSource), typeof(TReturnValue));
return Expression.Lambda(delegateType, Visit(node.Body), node.Parameters);
}
protected override Expression VisitMember(MemberExpression node)
{
if (node.Member.DeclaringType == typeof(TSource))
return Expression.Property(Visit(node.Expression), node.Member.Name);
return base.VisitMember(node);
}
}
[Test]
public void CanChangeFuncReturnTypeFromEnumToInt()
{
Expression<Func<MyEntity, MyEnum?>> enumExpression = p => p.EnumValue;
Expression<Func<MyEntity, int?>> intExpression = (Expression<Func<MyEntity, int?>>)new ReturnTypeVisitor<MyEntity, int?>().Visit(enumExpression);
var value = intExpression.Compile().Invoke(new MyEntity { EnumValue = MyEnum.One });
value.Should().Be(1);
}
public enum MyEnum
{
One = 1,
Two = 2
}
public class MyEntity
{
public MyEnum? EnumValue { get; set; }
}
Exception
System.ArgumentException : Expression of type 'System.Nullable`1[Xxx.Filtering.ReturnTypeVisitorVerifications+MyEnum]' cannot be used for return type 'System.Nullable`1[System.Int32]'
at System.Linq.Expressions.Expression.ValidateLambdaArgs(Type delegateType, Expression& body, ReadOnlyCollection`1 parameters)
at System.Linq.Expressions.Expression.Lambda(Type delegateType, Expression body, String name, Boolean tailCall, IEnumerable`1 parameters)
at System.Linq.Expressions.Expression.Lambda(Type delegateType, Expression body, IEnumerable`1 parameters)
at Filtering.ReturnTypeVisitor`2.VisitLambda[T](Expression`1 node) in xxxReturnTypeVisitor.cs:line 11
at Xxx.Filtering.ReturnTypeVisitorVerifications.CanChangeFuncReturnTypeFromEnumToInt() in yyyReturnTypeVisitorVerifications.cs:line 26
The question
How can I change the ReturnTypeVisitor
to work with value types, or is there another way of converting the expression?
question from:
https://stackoverflow.com/questions/65904862/change-return-type-of-expressionfunc-with-value-types 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…