2014-11-26 1 views
0

OrientDB .Net 라이브러리에 일부 확장 메서드를 작성하고 데이터베이스의 C# 및 그래프 (및 그 반대로) 모델 클래스 간의 매핑 작업을하고 있습니다. 이것은 반드시 약간의 반영과 동적 프로그래밍이 필요합니다.동적 목록 <T>. throwing 추가 RuntimeBinderException

다음 방법은 정점 사이의 모서리를 나타내는 모델 오브젝트의 특성 값을 설정하는 데 사용됩니다. 예를 들어, 정점 A가 모서리 C가있는 여러 개의 정점 B에 연결되어있는 경우 A 모델의 유형은 List<B>이고 B 모델의 속성은 A (일대 다 관계) 일 수 있습니다. 모델의

private static void SetLinkedProperty(
    ABaseModel parent, ABaseModel child, string className) 
{ 
    PropertyInfo[] properties = parent.GetType() 
     .GetProperties(BindingFlags.Public | 
         BindingFlags.Instance | 
         BindingFlags.SetProperty | 
         BindingFlags.GetProperty); 
    PropertyInfo propertySingle = properties 
     .Where(prop => IsModelProperty(prop, className)).SingleOrDefault(); 
    PropertyInfo propertyCollection = properties 
     .Where(prop => IsModelCollectionProperty(prop, className)).SingleOrDefault(); 
    if (propertySingle != null) 
    { 
     propertySingle.SetValue(parent, child); 
    } 
    if (propertyCollection != null) 
    { 
     dynamic propertyValue = propertyCollection.GetValue(parent); 
     if (propertyValue == null) 
     { 
      Type listOfT = typeof(List<>).MakeGenericType(
       propertyCollection.PropertyType.GenericTypeArguments[0]); 
      IEnumerable collection = (IEnumerable)Activator.CreateInstance(listOfT); 
      propertyValue = collection; 
      propertyCollection.SetValue(parent, collection); 
     } 

     propertyValue.Add(child); 
    } 
} 

속성 때문에 속성 유형이 별명에 대한뿐만 아니라 여부 IsModelPropertyIsModelCollectionProperty 확인이 열거 형은 그들에게 DB와 C# 클래스 사이의 매핑을 돕기 위해 별칭을주는 속성을 가질 수있다. 내 코드를 실행하면

그러나, 나는 선 propertyValue.Add(child)에서 RuntimeBinderException을 받고 있어요 :

형 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException'의 처리되지 않은 예외가 OrientTest.exe

발생

추가 정보 :에 가장 적합한 오버로드 된 메서드에 일치 'System.Collections.Generic.List.Add (OrientTest.Participant는)'의 시점에서 일부 잘못된 인수

있다 예외 :

  • parentOrientTest.Participant
  • className 인스턴스 OrientTest.Employer
  • child의 인스턴스는 "EmployerParticipant"(고용주와 참가자를 연결하는 에지 클래스의 이름이 DB에 함께 정점)이다
  • properties은 7 개의 요소를 포함하며, 각 요소는 하나의 속성에 해당합니다. Employer
  • propertySingle은입니다.
  • propertyCollectionList<Participant>#Add(Participant)가 유효하지 않은 인수가 왜 이해가 안 List<Participant>

의 인스턴스는 해당 부동산 List<Participant> Participants

  • propertyValue을 나타내지 만 dynamic은 종종 이상한 일을한다.

  • 답변

    1

    형식이 child 인 경우 ABaseModel이 아니고 OrientTest.Participant이 아니기 때문에 과부하 해결에 실패했습니다. 런타임시 그 값이 메소드가 예상하는 유형이되는 것은 중요하지 않습니다. 이것은 RuntimeBinder이라는 이름으로 반 직관적으로 보입니다.하지만 과부하 해결에 대한 규칙은 런타임에 적용되지만 컴파일시에 C#에서 사용하는 것과 동일합니다 (dynamic은 실제로 아주 오래된 C# 객체이기 때문에). 이것으로부터 벗어나는 것은 더 많은 놀라움을 가져올 것입니다.

    당신은 물론, 무시하거나 자신의 DynamicObject 구현을 작성하는 경우이 문제를 회피, 그래서 이것은 dynamic의 일반적인 제한없는 수 - 그것은 단지 당신이 (AB)의 실행시에 메소드 분석을 할 dynamic를 사용 할 수 없음을 의미 이 방법.

    IList propertyValue = (IList) propertyCollection.GetValue(parent); 
    ... 
    propertyValue.Add(child); 
    

    : 당신은 속성이 일부 T 항상 형 List<T>의 알고있는 경우 List<T>이 오래된 object (발생 가능한 런타임 예외를) 받아 IList를 구현하므로이 경우

    는 간단한 수정있다 당신이 목록의 알 수없는 경우, 당신은 동적으로 Add 방법을 총알을 물고 호출해야합니다 :

    차례로
    object propertyValue = propertyCollection.GetValue(parent); 
    ... 
    propertyValue.GetType().GetMethod("Add").Invoke(propertyValue, child); 
    

    이 실패 개체에 "가장 정확한"방법을 사용하려는 여러 .Add() 방법이있는 경우 우리가 그 특별한 사건을 다룰 필요가 없다고 가정하고 있습니다.

    실제로는 세 번째 접근법입니다. 여기에 잔인 함이 있지만 다른 상황에서 유용 할 수 있습니다. 즉, 인수 자체를 dynamic으로 만드는 것이므로 런타임에 해상도가 "옳은 일"을 수행하도록 강요됩니다 (일부 값은 "right") :

    propertyValue.Add((dynamic) child);