C# 如何调用反射函数<;T、 T>;使用表达式树的属性

C# 如何调用反射函数<;T、 T>;使用表达式树的属性,c#,linq-expressions,C#,Linq Expressions,我有一个泛型类,其lambda属性定义如下: public class Transformation<TProperty> : TransformationBase { public Func<TProperty, TProperty> Transform { get; private set; } ... 因此,以手写为例,其中TProperty是string,它应该是: Foo foo = ... // coming from an exte

我有一个泛型类,其lambda属性定义如下:

public class Transformation<TProperty> : TransformationBase
{
    public Func<TProperty, TProperty> Transform { get; private set; }
    ...
因此,以手写为例,其中TProperty是string,它应该是:

    Foo foo = ... // coming from an external source
    Transformation<string> tranformation = ... // coming from an external source
    foo.Value = transformation.Transform((string)foo.Value);
Foo-Foo=…//来自外部来源
转换转换=…//来自外部来源
foo.Value=transformation.Transform((字符串)foo.Value);
除了我不知道转换的确切类型,因为它是在外部程序集中定义的。因此,它可以是int或其他形式,而不是string。这就是为什么我想使用表达式树为给定的转换编译操作,以便调用:

    Foo foo = ... // coming from an external source
    TransformationBase transformation = ... // coming from an external source
    Action<Foo> transform = Compile(transformation);
    transform(foo); // should transform foo.Value using the Transform property of 'transformation'
Foo-Foo=…//来自外部来源
TransformationBase转换=…//来自外部来源
动作转换=编译(转换);
变换(foo);//应使用“transformation”的transform属性转换foo.Value

注意:我让Transformation继承自TransformationBase,以澄清此讨论。

不确定您想做什么,但如果我理解您的意图,我认为没有必要编译
表达式:

private static Action<TProperty> Compile<TProperty>(Transformation<TProperty> transformation)
{
    return new Action<TProperty>(p => transformation.Transform(p));
}
私有静态操作编译(转换)
{
返回新操作(p=>transformation.Transform(p));
}

看一个例子,它应该会给你想要的

void Main()
{

    var dummyObject = new Dummy { Test = "Hello!" };

    var propertyTransform = Create(dummyObject, "Test");

    propertyTransform(dummyObject);

    Console.WriteLine("Final transformation " + dummyObject.Test);
}

class Dummy {
    public string Test { get; set; }
}

// Define other methods and classes here
public class Transformation<TProperty>
{
    public Func<TProperty, TProperty> Transform { get; set; }
}

public static Action<TObj> Create<TObj>(TObj myObject, string property){
    var prop = myObject
        .GetType()
        .GetProperty(property);

    var val = prop.GetValue(myObject);

    var transformation = Create((dynamic)val);
    var transform = transformation.Transform;

    return obj => {

        var newValue = transform((dynamic)val);

        prop.SetValue(myObject, newValue);
    };
}

public static Transformation<TProperty> Create<TProperty>(TProperty property){

    var transformation = new Transformation<TProperty>();

    // just a dummy hijacking.
    if(typeof(TProperty)==typeof(string)){

        Func<string, string> test = input => "I am changed man!";

        transformation.Transform = (dynamic)test;
    }

    return transformation;
}
void Main()
{
var dummyObject=newdummy{Test=“Hello!”};
var propertyTransform=创建(dummyObject,“测试”);
属性转换(dummyObject);
Console.WriteLine(“最终转换”+dummObject.Test);
}
类虚拟{
公共字符串测试{get;set;}
}
//在此处定义其他方法和类
公共阶级转型
{
公共Func变换{get;set;}
}
公共静态操作创建(TObj myObject,字符串属性){
var prop=myObject
.GetType()
.GetProperty(property);
var val=属性GetValue(myObject);
var转换=创建((动态)val);
var transform=transform.transform;
返回obj=>{
var newValue=转换((动态)val);
属性设置值(myObject,newValue);
};
}
公共静态转换创建(TProperty属性){
var转换=新转换();
//只是一次假劫持。
if(typeof(TProperty)=typeof(string)){
Func test=input=>“我变了!”;
Transform=(动态)测试;
}
回报转化;
}
输出:

最后的转变我变了


你的问题更多地与你的问题周围没有打字有关
Foo.Value
是松散类型的,但是您的转换函数是强类型的。表达式树也是强类型的。使用它们不允许您以松散类型的方式神奇地调用代码

解决方案要么是大量的反射,要么是一些简单的动态:

编辑:我添加了CompileUnited,它使用ExpressionTrees。我还添加了CompileReflection,它使用反射而不使用ExpressionTrees。我推荐使用dynamic的。它是迄今为止最容易阅读的,因此也是最容易维护的

class Program
{
    static void Main(string[] args)
    {
        var testTransform = new Transformation<string>
            {
                Transform = s => s.ToUpper()
            };
        var a = Compile(testTransform);
        var foo = new Foo
            {
                Value = "test"
            };

        a(foo);

        //foo.Value is now TEST
    }

    public static Action<Foo> CompileReflection(TransformationBase transformation)
    {
        var f = transformation
            .GetType()
            .GetProperty("Transform")
            .GetGetMethod()
            .Invoke(transformation, null) as Delegate;

        return foo => foo.Value = f.DynamicInvoke(foo.Value);

    }

    public static Action<Foo> Compile(TransformationBase transformation)
    {
        return new Action<Foo>(f =>
            {
                dynamic d = f.Value;
                dynamic t = transformation;
                f.Value = t.Transform(d);
            });
    }

    public static Action<Foo> CompileUntyped(TransformationBase transformation)
    {
        var transformType = transformation.GetType();
        var genericType = transformType.GetGenericArguments().First();

        var fooParam = Expression.Parameter(typeof(Foo), "f");

        var valueGetter = typeof(Foo).GetProperty("Value").GetGetMethod();
        var valueSetter = typeof(Foo).GetProperty("Value").GetSetMethod();
        var transformFuncMember = transformType.GetProperty("Transform").GetGetMethod();

        //Equivalent to f => f.Value = transformation.Transform((T)f.Value)
        //Where T is the generic type parameter of the Transformation, and f is of type Foo
        var expression = Expression.Lambda<Action<Foo>>(
            Expression.Call(
                fooParam,
                valueSetter,
                Expression.Invoke(
                    Expression.Property(
                        Expression.Constant(transformation, transformType), 
                        transformFuncMember
                    ),
                    Expression.Convert(
                        Expression.Property(fooParam, valueGetter),
                        genericType
                    )
                )
            ), fooParam
        );
        return expression.Compile();
    }

}

public class TransformationBase { }

public class Transformation<TProperty> : TransformationBase
{
    public Func<TProperty, TProperty> Transform { get; set; }
}

public class Foo
{
    public object Value { get; set; }
}
类程序
{
静态void Main(字符串[]参数)
{
var testTransform=新转换
{
Transform=s=>s.ToUpper()
};
var a=编译(testTransform);
var foo=新foo
{
Value=“测试”
};
a(foo);
//值现在是TEST
}
公共静态操作编译器反射(TransformationBase转换)
{
var f=变换
.GetType()
.GetProperty(“转换”)
.getMethod()
.作为委托调用(转换,null);
返回foo=>foo.Value=f.DynamicInvoke(foo.Value);
}
公共静态操作编译(TransformationBase转换)
{
返回新操作(f=>
{
动态d=f.值;
动态t=变换;
f、 值=t.变换(d);
});
}
公共静态操作编译器已启用(TransformationBase转换)
{
var transformType=transformation.GetType();
var genericType=transformType.GetGenericArguments().First();
var fooParam=Expression.Parameter(typeof(Foo),“f”);
var valueGetter=typeof(Foo).GetProperty(“值”).getMethod();
var valueSetter=typeof(Foo).GetProperty(“值”).GetSetMethod();
var transformFuncMember=transformType.GetProperty(“Transform”).GetMethod();
//等价于f=>f.Value=transformation.Transform((T)f.Value)
//其中T是转换的泛型类型参数,f是Foo类型
var expression=expression.Lambda(
表情,打电话(
fooParam,
估价师,
表达式.调用(
表达式.属性(
表达式.常量(转换,转换类型),
转换函数成员
),
表达式。转换(
Expression.Property(fooParam,valueGetter),
泛型
)
)
),fooParam
);
返回表达式.Compile();
}
}
公共类转换基{}
公共类转换:TransformationBase
{
公共Func变换{get;set;}
}
公开课Foo
{
公共对象值{get;set;}
}

我不太明白这个问题。
Foo
TProperty
之间有什么关系?
转换
转换
之间有什么关系?
Compile
方法是否在
Transformation
类上?使用表达式树是一项要求,还是仅仅是您的att方式
void Main()
{

    var dummyObject = new Dummy { Test = "Hello!" };

    var propertyTransform = Create(dummyObject, "Test");

    propertyTransform(dummyObject);

    Console.WriteLine("Final transformation " + dummyObject.Test);
}

class Dummy {
    public string Test { get; set; }
}

// Define other methods and classes here
public class Transformation<TProperty>
{
    public Func<TProperty, TProperty> Transform { get; set; }
}

public static Action<TObj> Create<TObj>(TObj myObject, string property){
    var prop = myObject
        .GetType()
        .GetProperty(property);

    var val = prop.GetValue(myObject);

    var transformation = Create((dynamic)val);
    var transform = transformation.Transform;

    return obj => {

        var newValue = transform((dynamic)val);

        prop.SetValue(myObject, newValue);
    };
}

public static Transformation<TProperty> Create<TProperty>(TProperty property){

    var transformation = new Transformation<TProperty>();

    // just a dummy hijacking.
    if(typeof(TProperty)==typeof(string)){

        Func<string, string> test = input => "I am changed man!";

        transformation.Transform = (dynamic)test;
    }

    return transformation;
}
class Program
{
    static void Main(string[] args)
    {
        var testTransform = new Transformation<string>
            {
                Transform = s => s.ToUpper()
            };
        var a = Compile(testTransform);
        var foo = new Foo
            {
                Value = "test"
            };

        a(foo);

        //foo.Value is now TEST
    }

    public static Action<Foo> CompileReflection(TransformationBase transformation)
    {
        var f = transformation
            .GetType()
            .GetProperty("Transform")
            .GetGetMethod()
            .Invoke(transformation, null) as Delegate;

        return foo => foo.Value = f.DynamicInvoke(foo.Value);

    }

    public static Action<Foo> Compile(TransformationBase transformation)
    {
        return new Action<Foo>(f =>
            {
                dynamic d = f.Value;
                dynamic t = transformation;
                f.Value = t.Transform(d);
            });
    }

    public static Action<Foo> CompileUntyped(TransformationBase transformation)
    {
        var transformType = transformation.GetType();
        var genericType = transformType.GetGenericArguments().First();

        var fooParam = Expression.Parameter(typeof(Foo), "f");

        var valueGetter = typeof(Foo).GetProperty("Value").GetGetMethod();
        var valueSetter = typeof(Foo).GetProperty("Value").GetSetMethod();
        var transformFuncMember = transformType.GetProperty("Transform").GetGetMethod();

        //Equivalent to f => f.Value = transformation.Transform((T)f.Value)
        //Where T is the generic type parameter of the Transformation, and f is of type Foo
        var expression = Expression.Lambda<Action<Foo>>(
            Expression.Call(
                fooParam,
                valueSetter,
                Expression.Invoke(
                    Expression.Property(
                        Expression.Constant(transformation, transformType), 
                        transformFuncMember
                    ),
                    Expression.Convert(
                        Expression.Property(fooParam, valueGetter),
                        genericType
                    )
                )
            ), fooParam
        );
        return expression.Compile();
    }

}

public class TransformationBase { }

public class Transformation<TProperty> : TransformationBase
{
    public Func<TProperty, TProperty> Transform { get; set; }
}

public class Foo
{
    public object Value { get; set; }
}