将 return 类型的表达式 <Func<,>> 更改为值类型
Change return type of Expression<Func<,>> with value types
我定义了一个 Expression<Func<TSource, T>>
,其 return 类型 (T
) 是一个 enum
。我正在使用这个和其他类似的表达式来投影和过滤带有 entity framework.
的项目
我还希望能够在只需要数值的上下文中使用此表达式,在这种情况下,将表达式传递/转换为 Expression<Func<TSource, T>>
,其中 T
的类型为 int?
.
我试过的
This post 展示了如何使用访问者模式在 object
和正常工作的引用类型之间更改 return 类型。但是,当对值类型尝试同样的事情时,它不起作用。
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; }
}
异常
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 xxx\ReturnTypeVisitor.cs:line 11
at Xxx.Filtering.ReturnTypeVisitorVerifications.CanChangeFuncReturnTypeFromEnumToInt() in yyy\ReturnTypeVisitorVerifications.cs:line 26
问题
如何更改 ReturnTypeVisitor
以使用值类型,或者是否有其他转换表达式的方法?
您可以创建一个扩展方法来转换原始 lambda 的结果:
public static class ExpressionExt {
public static Expression<Func<TSource,int?>> ConvertToNullableInt<TSource, TEnum>(this Expression<Func<TSource,TEnum>> src)
=> Expression.Lambda<Func<TSource,int?>>(Expression.Convert(src.Body, typeof(int?)), src.Parameters);
}
然后您可以像这样使用它:
Expression<Func<Test,TestEnum>> f = t => t.e;
var g = f.ConvertToNullableInt();
我定义了一个 Expression<Func<TSource, T>>
,其 return 类型 (T
) 是一个 enum
。我正在使用这个和其他类似的表达式来投影和过滤带有 entity framework.
我还希望能够在只需要数值的上下文中使用此表达式,在这种情况下,将表达式传递/转换为 Expression<Func<TSource, T>>
,其中 T
的类型为 int?
.
我试过的
This post 展示了如何使用访问者模式在 object
和正常工作的引用类型之间更改 return 类型。但是,当对值类型尝试同样的事情时,它不起作用。
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; }
}
异常
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 xxx\ReturnTypeVisitor.cs:line 11
at Xxx.Filtering.ReturnTypeVisitorVerifications.CanChangeFuncReturnTypeFromEnumToInt() in yyy\ReturnTypeVisitorVerifications.cs:line 26
问题
如何更改 ReturnTypeVisitor
以使用值类型,或者是否有其他转换表达式的方法?
您可以创建一个扩展方法来转换原始 lambda 的结果:
public static class ExpressionExt {
public static Expression<Func<TSource,int?>> ConvertToNullableInt<TSource, TEnum>(this Expression<Func<TSource,TEnum>> src)
=> Expression.Lambda<Func<TSource,int?>>(Expression.Convert(src.Body, typeof(int?)), src.Parameters);
}
然后您可以像这样使用它:
Expression<Func<Test,TestEnum>> f = t => t.e;
var g = f.ConvertToNullableInt();