2014-11-18 4 views
-1

표현의 나무를 사용하여 반영 Func을 속성을 호출 할 수 있습니다 Foo의 재산에). 나는 컴파일 타임에 TProperty를 모른다. 나는 이것으로 시작했습니다 : 어떻게 내가 같은 정의 람다 속성과 제네릭 클래스를

private static Action<Foo> Compile(Transformation transformation) 
    { 
     var fooParameter = Expression.Parameter(typeof(Foo)); 
     var changePropertyValue = Expression.Constant(transformation); 
     var transformProperty = Expression.Property(changePropertyValue, "Transform"); 
     var transfromCall = Expression.Call(transformProperty, ? 
    } 

transformProperty를 어떻게 호출 할 수 있습니까?

EDIT : 푸 (컴파일 시간이라고한다)이 필요 지정되지 않은 속성 값이 변환의 변환 속성을 사용하여 형질 전환되어야한다 :

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

그래서, 예를 들어 손으로 쓴 어디 TProperty 문자열은 다음과 같습니다.

Foo foo = ... // coming from an external source 
    Transformation<string> tranformation = ... // coming from an external source 
    foo.Value = transformation.Transform((string)foo.Value); 

외부 어셈블리에서 정의 된대로 정확한 변환 유형을 알지 못합니다. 따라서 문자열 대신 int 또는 다른 것이 될 수 있습니다.

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' 

참고 : 내가 호출 할 수 있도록 주어진 변화에 대한 작업을 컴파일 표현의 나무를 사용하려는 이유 나는 변환이 토론을 명확히하기 위해 TransformationBase에서 상속했다. 당신이하려고하지만 난 당신의 의도를 이해한다면 어떤

+2

나는 그 질문을 정말로 이해하지 못한다. 'Foo'와'TProperty'의 관계는 무엇입니까? '변환'과 '변환 '의 관계는 무엇입니까? '변환 '클래스의'Compile' 메소드가 있습니까? 표현식 트리를 사용하고 있습니까? 아니면 표현식 트리를 어떻게 사용하고 있습니까? –

+0

코드의 아주 작은 예를 제공하면 이해하기가 훨씬 쉬울 것입니다. 예를 들어,'행동'이 실제로해야 할 일이 있습니다. –

+0

@BenAaronson :'컴파일 '은'변환 '과'Foo' 밖에 있습니다. 내 추가 설명이 명확 해지기를 바랍니다. – Dejan

답변

1

가 문제가 당신의 문제를 해결 입력의 부족으로 더 많은 관련이있다. Foo.Value은 느슨하게 입력되었지만 사용자의 변환 함수는 강하게 입력됩니다. 표현식 트리도 강하게 입력됩니다. 그것들을 사용하면 마술처럼 느슨한 형식으로 코드를 호출 할 수 없습니다.

EDIT :

용액 반사 많이, 또는 쉽게 동적 일이며 I는 ExpressionTrees.I도 ExpressionTrees없이 반사를 사용 CompileReflection을 첨가 사용 CompileUntyped 첨가. 나는 동적 인 것을 사용하는 것을 권할 것이다. 읽기가 훨씬 쉬워 유지하기가 가장 쉽습니다.

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; } 
} 
+0

예, 가능한 해결책이며 예, 내 문제는 타이핑과 관련하여 조금 이상합니다. 하지만 제 질문은 일반적인 질문입니다. Exrpression Trees를 사용하여 Func 유형의 속성을 호출하려면 어떻게해야합니까? 그리고 이것은 아무도 지금까지 대답하지 않았습니다. – Dejan

+0

이 문제를 해결하기 위해 편집되었습니다. – Shlomo

0

확실하지 - 내가 Expressions 컴파일에 필요한 표시되지 않습니다 :

private static Action<TProperty> Compile<TProperty>(Transformation<TProperty> transformation) 
{ 
    return new Action<TProperty>(p => transformation.Transform(p)); 
} 
+0

죄송합니다. 첫 번째 샷이 너무 짧습니다. 액션이'TProperty'가 아니라'Foo'에 대해 행동해야한다는 것은 이제 분명해야합니다. – Dejan

0

는 예를 참조하십시오, 당신이 원하는 무엇을 제공해야합니다.

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; 
} 

출력 :

Final transformation I am changed man!

+0

죄송합니다. 첫 번째 샷이 너무 짧습니다. 나는 설명에 더 많은 것을 추가 했으므로'Foo'는'Transformation '의'TProperty'가 아닌 컴파일 타임으로 알려진 타입입니다. 그래서 당신의 제안은 도움이되지 않습니다. – Dejan

+0

@Dejan :'Action = (Foo foo) => transformation.Transform ((동적) (foo.Value))'가 작동해야합니다. –

+0

'변환 '에 정의 된대로'변환 '을 호출 할 수 없습니다. 나는 단지'TransformationBase' 타입의 인스턴스에 대한 참조만을 가지고 있습니다. – Dejan