2009-10-17 2 views
2

현재 노드 편집기 (as in Blender)를 만들고 있는데 대리인을 제네릭 형식에서 속성 접근 자로 가져 오는 데 문제가 있습니다. 지금까지 질문이 here에 가깝다는 것을 알게되었지만, 나는 일반적으로 객체 유형과 관련이 있다고 생각합니다.제네릭 형식의 속성 접근 자의 대리인을 얻으려면 어떻게해야합니까?

"노드"는 객체와 동의어이며 "포트"는 속성과 동의어입니다.

이것은 위반 코드이며 Node 클래스의 일부입니다. NodePort 클래스는 속성에 대해 설정되어 속성에 대한 세부 정보 (예 : 사람이 읽을 수있는 이름 및 데이터 흐름 방향)를 제공 할 수있는 속성입니다.

public void SetTarget<T>(T Target) 
{ 
    //TODO: Finish clearing old IOs (if any) 
    Inputs.Clear(); 
    Outputs.Clear(); 

    //Keep track of the current target of this node. 
    ThisTarget = Target; 

    PropertyInfo[] pinfo = Target.GetType().GetProperties(); 

    foreach (PropertyInfo property in pinfo) 
    { 
     Attribute[] attrs = Attribute.GetCustomAttributes(property); 
     foreach (Attribute attribute in attrs) 
     { 
      // If the property has a NodePort attribute, it's specifically requesting to be available as a port on the node. 
      if (attribute is NodePort) 
      { 
       NodePort PortDetails = (NodePort)attribute; 

       if (PortDetails.Direction == NodePort.NodePortDirection.PORT_INPUT) 
       { 
        // This line throws an ArgumentException, and the only message is "Error binding to target method." 
        NodeInput<T>.SetValue Setter = (NodeInput<T>.SetValue)Delegate.CreateDelegate(typeof(NodeInput<T>.SetValue), (T)Target, property.GetSetMethod()); 
        AddInput(Setter, PortDetails.CommonName); 
       } 
       else if (PortDetails.Direction == NodePort.NodePortDirection.PORT_OUTPUT) 
       { 
        // Same exception here. 
        NodeOutput<T>.GetValue Getter = (NodeOutput<T>.GetValue)Delegate.CreateDelegate(typeof(NodeOutput<T>.GetValue), (T)Target, property.GetGetMethod()); 
        AddOutput(Getter, PortDetails.CommonName); 
       } 
      } 
     } 

    } 
} 

NodeOutput<T>.GetValueNodeInput<T>.SetValue는 같은 정의된다

public delegate T GetValue(); 
public delegate void SetValue(T value); 

... 각각 NodeOutputNodeInput있다.

누구나 속성 접근 자의 대리인을 만드는 경험이 있습니까? 문제의 유형이 제네릭 일 때 어떻게 다른지 알기 원하십니까?

+0

모든 유형의 속성을 * NodePort *로 장식 할 수 있습니까? – Elisha

+0

예. 'NodePort'는 어떤 속성에도 적용될 수 있습니다. –

답변

1

여기에는 유형이 일치하지 않는다고 생각됩니다. 첫 번째 예외 행에서 setterNodeInput<T> 유형으로 선언됩니다. 즉, T를 취하여 void를 반환하는 메서드입니다. 그러나 setter에 할당하는 메서드는 property.PropertyType을 취해 void를 반환하는 메서드 인 property.GetSetMethod()입니다. 행운에 의해 예외가 발생하지 않는 한 property.PropertyType은 T와 동일합니다. 마찬가지로 예외 행의 두 번째에있는 getter에 대해 예외가 발생합니다.

제네릭을 사용하여 처리 할 수 ​​없다고 생각합니다. 왜냐하면 컴파일 타임에 property.PropertyType을 모르므로 해당 유형을 일반 매개 변수로 전달할 수 없기 때문입니다 (일반 매개 변수는 컴파일 타임에 지정해야하기 때문에 , type.MakeGenericType을 사용하지 않는 한).

+0

Delegate.CreateDelegate의 목적으로 사용 된 것으로, type (typeof (NodeInput .GetSetter)), 대상 (Target) 및 MethodInfo (property.GetSetMethod())를 허용합니다. GetSetMethod()의 MethodInfo는 단순한 setter를 설명합니다. void (T)를 설정합니다. http://msdn.microsoft.com/en-us/library/system.reflection.propertyinfo.getsetmethod(VS.71).aspx –

+1

그러나 GetSetMethod의 MethodInfo가 void Set (T)와 일치하지 않습니다. void Set (property.PropertyType)과 일치합니다. property.GetSetMethod를 임시 변수에 넣고 디버거에서 검사하십시오. 예를 들어, T에 int 유형의 Foo 속성이 있다고 가정합니다. 그런 다음 루프에서 Property가 Foo의 PropertyInfo 일 때 property.GetSetMethod는 int => void 유형이되고 Foo 속성 setter는 T가 아닌 int를 사용하기 때문에 T => void 유형이 아닙니다. set 메소드는 다음과 같습니다. * T에 선언 *, T를 받아 들일 수 없음 * – itowlson

+0

알았어, 네, 맞아. 그래서 지금 질문을 추측합니다, 어떻게 System.Type 떨어져 일반 개체를 인스턴스화합니까? System.Type 속성에서 있지만 일반 (이 경우 내 대리자 setter) 인스턴스를 만드는 데 사용하는 방법을 모르겠습니다. –

1

속성 접근 자의 대리인을 만들려면 GetGetMethodGetSetMethod을 사용하면됩니다. 그것이 어디에서 붕괴되고 있는지 설명 할 수 있습니까?

단순화 된 예 :베이스 클래스 등을 포함하는 트릭이 단지 object에 일을 처리 할 수 ​​

using System; 
class Foo<T> 
{ 
    public T Value { get; set; } 
} 
static class Program 
{ 
    static void Main() 
    { 
     var obj = new Foo<int> { Value = 123 }; 
     var prop = obj.GetType().GetProperty("Value"); 
     Func<Foo<int>, int> getter = (Func<Foo<int>, int>) 
      Delegate.CreateDelegate(
       typeof(Func<Foo<int>, int>), prop.GetGetMethod()); 
     int x = getter(obj); 
     Console.WriteLine(x); 
     Action<Foo<int>, int> setter = (Action<Foo<int>, int>) 
      Delegate.CreateDelegate(
       typeof(Action<Foo<int>, int>), prop.GetSetMethod()); 
     setter(obj, 321); 
     Console.WriteLine(obj.Value); 
    } 
} 

주 - 혹은 HyperDescriptor 같은 것들을 고려는; 유사한 성능,하지만 훨씬 간단합니다, 당신은 단지 (을 활성화 한 후) PropertyDescriptorobject을 사용하기 때문에 :

var prop = TypeDescriptor.GetProperties(obj)["Value"]; 
object val = prop.GetValue(prop); 
prop.SetValue(prop, 321); 

마지막 옵션은 Expression입니다; 자산 접근을위한 다양한 트릭을 Expressionthis series에 포함합니다.

관련 문제