2017-12-11 19 views
0

리플렉션을 사용하여 구조의 모든 부분에 대해 MemberExpression을 확인하려고합니다.리플렉션 및 상속 문제 C#

 Entity entity = new Entity() { FirstPart = new Part() { Id = 1 } }; 

기능은 다음과 같습니다 :

public class Entity 
{ 
    public Part FirstPart { get; set; } 
} 

public class Part 
{ 
    public int Id { get; set; } 
} 

public class SubPart : Part 
{ 
    public int ExtraProperty { get; set; } 
} 

내가 모든 구성 요소의 MemberExpression을 결정하는 데 사용되는 기능, 다음 개체 구조에 대해 잘 작동 :이 문제를 설명하기 위해 개체의 일부입니다

 var param = Expression.Parameter(entity.GetType()); 
     String[] childProperties = ("FirstPart.Id").Split('.'); 
     var propExpression = Expression.PropertyOrField(param, childProperties[0]); 
     for (int i = 1; i < childProperties.Length; i++) 
     { 
      propExpression = Expression.PropertyOrField(propExpression, childProperties[i]); 
     } 

하지만이 때문에 상속하려면 다음 작동하지 않습니다 :

 Entity entity = new Entity() { FirstPart = new SubPart() { ExtraProperty = 1 } }; 

우리가 "FirstPart.ExtraProperty"의 경로를 변경해야하는 속성을 되돌아하기 위해 'ExtraProperty은'파트의 구성원이 아닌 :

 var param = Expression.Parameter(entity.GetType()); 
     String[] childProperties = ("FirstPart.ExtraProperty").Split('.'); 
     var propExpression = Expression.PropertyOrField(param, childProperties[0]); 
     for (int i = 1; i < childProperties.Length; i++) 
     { 
      propExpression = Expression.PropertyOrField(propExpression, childProperties[i]); 
     } 

오류 메시지가 나와 있습니다. 누구든지이 문제를 극복하는 방법을 알고 있습니까?

+1

캐스팅해야합니다. – SLaks

+1

그것에 대해 생각해 보면, 'entity.FirstPart.ExtraProperty = 5;'를 수행 할 수 없습니다. 캐스트가 없으면 Expression이 달라지지 않습니다. – DavidG

+0

답장을 보내 주셔서 감사합니다. 예를 들어 주조 과정을 설명해 주시겠습니까? –

답변

3

수 없습니다. 표현식은 컴파일 타임 대신 런타임에 컴파일되는 코드라고 생각하십시오. 마술과 비슷한 규칙이 적용됩니다 (표현식이 낮고 제한적이므로 C# 코드 수준에서 사용할 수있는 많은 구문 설탕은 표현식에서 사용할 수 없습니다). 그렇다면 entity.FirstPart.ExtraProperty은 C# 코드에서 유효하지 않으므로 표현식에서도 유효하지 않습니다.

당신은 명시 적 캐스트를 삽입 할 수 -하지만 당신이 그 인스턴스가 실제로 유형 SubPart이 될 것입니다 가정, 그렇게하지 않는 이유는 유형 SubPart 대신 Part의 멤버 FirstPart을 정의합니다. 또는 TypeIs expression을 사용하여 형식 테스트 논리를 만든 다음 C# 코드에서와 같은 방식으로 캐스팅 할 수 있습니다.

편집 :

문제를 다시 읽어 후, 나는 당신이 실제로 구현하려고하는 것은 재산 워커는 임의의 객체를 초과 것을 알 수있다. 그러므로 TypeIs 표현식은 컴파일 타임에 테스트 할 유형을 요구하기 때문에 여기서는 도움이되지 않습니다. 그러나 귀하의 경우 임의의 추가 속성이있는 FirstPart 회원에 Part에서 파생 된 임의의 클래스가있을 수 있습니다. 이 경우 다른 옵션은 없지만 각 속성을 하나씩 평가하고 중간 값에서 실제 유형을 검색합니다. 예 :

Entity entity = new Entity() { FirstPart = new SubPart() { ExtraProperty = 1 } }; 

object currentObjectInChain = entity; 
String[] childProperties = ("FirstPart.ExtraProperty").Split('.'); 

foreach (var property in childProperties) 
{ 
    if (currentObjectInChain == null) 
    { 
     throw new ArgumentException("Current value is null"); 
    } 
    var type = currentObjectInChain.GetType(); 
    var param = Expression.Parameter(type); 
    var lambda = Expression.Lambda(
     Expression.PropertyOrField(param, property), 
     param).Compile(); // cache based on type and property name 
    currentObjectInChain = lambda.DynamicInvoke(currentObjectInChain); 
} 

루프의 끝에서 currentObjectInChain이 값을 유지합니다.

+0

동일한 기본 클래스의 다른 하위 클래스가있을 수 있으므로 Part FirstPart를 Part가 아닌 SubPart로 정의 할 수는 없다고 가정해야합니다. TypeIs를 알지 못하며이 경우 어떻게 캐스트 할 수 있는지 보지 못합니다. 예를 들어 자세히 설명해 주시겠습니까? 미리 감사드립니다 –

+0

그냥 내가 뭘 찾고 있었는지, 감사합니다 :) –