C# 更改表达式的返回类型<;func<&燃气轮机&燃气轮机;

C# 更改表达式的返回类型<;func<&燃气轮机&燃气轮机;,c#,linq-expressions,C#,Linq Expressions,假设我有一个表达式是否可以基于类型变量将返回类型动态更改为类似表达式 我有以下课程: public class ImportCheck<T> { public int id { get; set; } public string Name { get; set; } public Type Type { get; set; } public bool Required { get; set; } public int? MinLength {

假设我有一个
表达式
是否可以基于
类型
变量将返回类型动态更改为类似
表达式

我有以下课程:

public class ImportCheck<T> {

    public int id { get; set; }
    public string Name { get; set; }
    public Type Type { get; set; }
    public bool Required { get; set; }
    public int? MinLength { get; set; }
    public int? MaxLength { get; set; }
    public string Value { get; set; }
    public Expression<Func<T, object>> AssociatedProperty { get; set; }
}

然后将其称为类似于
MakeSet(member)(target,value)
,其中member是
表达式
target
是对象,
value
是要将属性设置为的值。

确定;您可以创建一个新的表达式树,将对象强制转换为您想要的任何类型(当然,强制转换不会包含任何担保对象),并且可以在新表达式树中使用旧表达式树的一部分(即整个lambda主体)

然而,即使您创建了这样一个东西,请注意,如果您想要静态地表示表达式的类型,例如
表达式
,您也需要静态地知道该类型。泛型可以工作,但运行时
类型
变量不行

您的方法存在几个问题:

  • 假设
    fetcherExp.Body
    是成员访问,例如
    obj.TheProperty
    。但是,如果表达式的类型为
    expression
    ,则任何值类型属性都将表示为“Convert(obj.TheProperty)”
  • 假设有一个setter对应于getter
  • 您假定
    类型
    属性是正确的
我建议你用不同的方法处理这个问题。与其处理类型不正确的
表达式
对象,并尝试从中生成setter(和getter?),我建议您从一个准确类型的
表达式
——甚至只是一个
属性信息
开始,并生成类型化的getter和setter。一旦有了
Func getter
Action setter
,就可以轻松地包装它们以生成不太具体的操作和函数:

public static Action<T,object> UntypeSetter<T,TProperty>(Action<T,TProperty> typedSetter) =>
    (o, val) => typedSetter(o, (TProperty)val);
publicstaticactionuntypesetter(actiontypedsetter)=>
(o,val)=>typedSetter(o,(TProperty)val);
类似的方法对getter很有用(但这只对值类型属性的getter很重要,因为协方差意味着引用类型getter都可以强制转换为
操作

如果您确实需要最大的运行时性能,您可以使用
Expression
s执行完全相同的包装技巧,并将嵌套调用内联到
typedSetter
,但请注意,您并没有赢得那么多;对于大多数应用程序来说,一次和两次委托调用之间的差异不大重要


TL;DR:不要使用
表达式
作为非类型属性的中间表示形式;这样做会丢弃对创建getter/setter有用的类型信息。相反,使用类型化表达式
表达式
可以轻松生成非类型化的getter和setter,并将它们作为中间表示进行传递。

请查找以下示例:

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);
    }
}
public类ReturnTypeVisitor:ExpressionVisitor{
受保护的重写表达式VisitLambda(表达式节点)
{
var delegateType=typeof(Func).MakeGenericType(typeof(TSource),typeof(TReturnValue));
返回表达式.Lambda(delegateType,Visit(node.Body),node.Parameters);
}
受保护的重写表达式VisitMember(MemberExpression节点)
{
if(node.Member.DeclaringType==typeof(TSource))
{
返回Expression.Property(访问(node.Expression)、node.Member.Name);
}
返回base.VisitMember(节点);
}
}
用法:

public class Foo{
    public Bar Bar { get; set; }
}

public class Bar { }

Expression<Func<Foo, object>> expression = p => p.Bar;
Expression<Func<Foo, Bar>> stronglyTypedReturnValue = (Expression<Func<Foo, Bar>>)new ReturnTypeVisitor<Foo, Bar>().Visit(expression);
公共类Foo{
公共条{get;set;}
}
公共类Bar{}
表达式=p=>p.Bar;
表达式stronglyTypedReturnValue=(表达式)新建ReturnTypeVisitor()。访问(表达式);

您能更详细地说明您要做什么吗?特别是包含的示例代码并不能完全满足您的要求?您能给出一个尝试设置子属性的示例吗?特别是,这是明确的逐案代码,还是以某种方式进行了推广?@eamonnerbnne补充了一些关于如何设置属性的细节。由于我的表达式结果是一个对象,这是作为一个单一表达式而不是MemberExpression出现的,这是导致我出现问题的原因我猜你是在试图抽象C#类上的属性,以委托处理对象的getter和setter,对吗?我将继续讨论这个问题,而不是讨论确切的问题,因为我认为它更有用(而且更容易做到)。谢谢,你有一个例子吗
public class Foo{
    public Bar Bar { get; set; }
}

public class Bar { }

Expression<Func<Foo, object>> expression = p => p.Bar;
Expression<Func<Foo, Bar>> stronglyTypedReturnValue = (Expression<Func<Foo, Bar>>)new ReturnTypeVisitor<Foo, Bar>().Visit(expression);