성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] 제가 큰 실수를 했군요. ^^; Delegate를 통한 Bein...
[정성태] Working with Rust Libraries from C#...
[정성태] Detecting blocking calls using asyn...
[정성태] 아쉽게도, 커뮤니티는 아니고 개인 블로그입니다. ^^
[정성태] 질문이 잘 이해가 안 됩니다. 우선, 해당 소스코드에서 ILis...
[양승조
] var대신 dinamic으로 선언해서 해결은 했습니다. 맞는 해...
[양승조
] 또 막혔습니다. ㅠㅠ var list = props[i].Ge...
[양승조
] 아. 감사합니다. 어제는 안됐던것 같은데....정신을 차려야겠네...
[정성태] "props[i].GetValue(props[i])" 코드에서 ...
[정성태] 저렇게 조각 코드 말고, 실제로 재현이 되는 예제 프로젝트를 압...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <div style='font-family: 맑은 고딕, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>System.Reflection.TargetException</div> <br /> 특수한 경우이긴 하지만. 기록을 남기는 차원에서. ^^<br /> <br /> 상황은 다음과 같습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > public class BaseA { public <b style='COLOR: blue'>int Field</b> { get; set; } } public class <b style='COLOR: blue'>DerivedB : BaseA</b> {} public class <b style='COLOR: blue'>DerivedC : BaseA</b> {} </pre> <br /> 위와 같은 구조에서 BaseA.Field를 접근하는 데 Reflection을 이용해서 다음과 같이 사용을 합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > static void Main(string[] args) { <b style='COLOR: blue'>DerivedB db</b> = new DerivedB(); Console.WriteLine(<b style='COLOR: blue'>GetFieldValue</b>(db)); <b style='COLOR: blue'>DerivedC dc</b> = new DerivedC(); Console.WriteLine(<b style='COLOR: blue'>GetFieldValue</b>(dc)); } <b style='COLOR: blue'>static PropertyInfo propertyInfo;</b> static int GetFieldValue(object instance) { if (propertyInfo == null) { <b style='COLOR: blue'>propertyInfo = instance.GetType()</b>.GetProperty("Field", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public); } return (int)propertyInfo.GetValue(instance, null); } </pre> <br /> 상황에 따라서, 해당 어셈블리를 직접 참조할 수 없어서 public 필드에 대한 접근조차도 Reflection을 이용해야 할 필요가 있습니다. 어쨌든, 위의 코드는 PropertyInfo를 캐쉬해서 정상적으로 대부분의 코드에서 잘 사용할 수 있었는데요.<br /> <br /> 예상치 않게, 특정 클래스에 대해 다음과 같은 오류가 발생했습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > <b style='COLOR: blue'>System.Reflection.TargetException occurred</b> Message=Object does not match target type. Source=mscorlib StackTrace: at System.Reflection.RuntimeMethodInfo.CheckConsistency(Object target) at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks) at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) at System.Reflection.RuntimePropertyInfo.GetValue(Object obj, BindingFlags invokeAttr, Binder binder, Object[] index, CultureInfo culture) at System.Reflection.RuntimePropertyInfo.GetValue(Object obj, Object[] index) at Jennifer40.Profiler.Interception.SoapHttpClientProtocolInvoke2000_Preprocess(Object thisObject, Boolean& bEndProcess, String arg1, Object[] arg2) InnerException: </pre> <br /> 갑자기 ^^; GetProperty를 사용한 Reflection에 대한 급(!) 회의감이 들었습니다.<br /> <br /> 위의 예에서는 문제를 간략화했기 때문에 분석이 간단하지만, 건드릴 수 없는 고객사의 복잡한 웹 애플리케이션 코드와 제 코드가 뒤섞여서 발생하는 상황이라면 저 정도의 오류 메시지로 문제 분석할 엄두가 나질 않습니다. ^^;<br /> <br /> (하지만, 삶은 계속되므로!) 문제를 분석하는 중... TargetException이 발생하는 클래스들의 공통점이 발견되었습니다. 바로, 해당 Field에 대해서 상속받은 클래스에서 재정의를 한 경우였습니다.<br /> <br /> 바로 이렇게, virtual/override 로 했거나,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > public class BaseA { public <b style='COLOR: blue'>virtual</b> int Field { get; set; } } public class DerivedB : BaseA { public <b style='COLOR: blue'>override</b> int Field { get; set; } } public class DerivedC : BaseA { public <b style='COLOR: blue'>override</b> int Field { get; set; } } </pre> <br /> 또는, new로 했거나,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > public class BaseA { public <b style='COLOR: blue'>int Field</b> { get; set; } } public class DerivedB : BaseA { public <b style='COLOR: blue'>new int Field</b> { get; set; } } public class DerivedC : BaseA { public <b style='COLOR: blue'>new int Field</b> { get; set; } } </pre> <br /> 그런 경우에, 아래와 같이 instance.GetType().GetProperty로 반환받으면 상속받은 클래스의 필드가 나오게 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > instance.GetType().GetProperty("Field", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public); </pre> <br /> 따라서, DerivedB.Field에 대한 PropertyInfo를 캐쉬하고 있었는데 DerivedC 인스턴스가 들어오니 System.Reflection.TargetException 예외가 발생한 것입니다.<br /> <br /> 이를 해결하려면?<br /> <br /> 만약, 기반 클래스의 Field 접근이 원하는 값을 반환해 준다면 다음과 같이 명시적인 타입을 지정해 줄 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > Type targetType = ...[BaseA 타입 구하는 코드]...; targetType.GetProperty(...); </pre> <br /> 그렇지 않다면, static 캐쉬를 포기해야 합니다. 그냥 인스턴스 변수에 저장해 놓고 그때그때의 타입에 따라 매번 GetProperty를 구해서 처리해야 합니다. (위의 경우에는 속성만 예를 들었지만, 일반 메서드의 경우에도 동일하게 적용되겠죠!)<br /> <br /> 결국은, ... <a target='_tab' href='/2/0/766'>이번 문제는 아는 게 병</a>이 된 좋은 사례라는. ^^;<br /> <br /><br /><hr /><span style='color: Maroon'>[이 토픽에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1626
(왼쪽의 숫자를 입력해야 합니다.)