내 클래스에는 개인 메소드 그룹이 있으며 입력 값을 기반으로 동적 메소드를 호출해야합니다. 호출 코드와 대상 메소드는 모두 동일한 인스턴스에 있습니다. 코드는 다음과 같습니다.
MethodInfo dynMethod = this.GetType().GetMethod("Draw_" + itemType);
dynMethod.Invoke(this, new object[] { methodParams });
이 경우 GetMethod()
개인용 메서드를 반환하지 않습니다. 개인 메소드를 찾을 수 있도록 무엇 BindingFlags
을 제공해야 GetMethod()
합니까?
답변
BindingFlags를 허용 하는 오버로드 된 버전GetMethod
을 사용하도록 코드를 변경하기 만하면 됩니다.
MethodInfo dynMethod = this.GetType().GetMethod("Draw_" + itemType,
BindingFlags.NonPublic | BindingFlags.Instance);
dynMethod.Invoke(this, new object[] { methodParams });
여기의 BindingFlags의 열거 설명서 .
답변
BindingFlags.NonPublic
자체적으로 결과를 반환하지 않습니다. 결과적으로 그것을 결합 BindingFlags.Instance
하면 트릭 을 수행합니다.
MethodInfo dynMethod = this.GetType().GetMethod("Draw_" + itemType,
BindingFlags.NonPublic | BindingFlags.Instance);
답변
그리고 정말로 어려움에 처하고 싶다면 확장 방법을 작성하여 쉽게 실행할 수 있도록하십시오.
static class AccessExtensions
{
public static object call(this object o, string methodName, params object[] args)
{
var mi = o.GetType ().GetMethod (methodName, System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance );
if (mi != null) {
return mi.Invoke (o, args);
}
return null;
}
}
그리고 사용법 :
class Counter
{
public int count { get; private set; }
void incr(int value) { count += value; }
}
[Test]
public void making_questionable_life_choices()
{
Counter c = new Counter ();
c.call ("incr", 2); // "incr" is private !
c.call ("incr", 3);
Assert.AreEqual (5, c.count);
}
답변
Microsoft는 최근 에 이러한 답변의 대부분을 더 이상 사용하지 않는 리플렉션 API를 수정했습니다 . 다음은 최신 플랫폼 (Xamarin.Forms 및 UWP 포함)에서 작동해야합니다.
obj.GetType().GetTypeInfo().GetDeclaredMethod("MethodName").Invoke(obj, yourArgsHere);
또는 확장 방법으로 :
public static object InvokeMethod<T>(this T obj, string methodName, params object[] args)
{
var type = typeof(T);
var method = type.GetTypeInfo().GetDeclaredMethod(methodName);
return method.Invoke(obj, args);
}
노트 :
-
원하는 메소드가 제네릭 의 수퍼 클래스에
obj
있는 경우 수퍼 클래스의T
유형으로 명시 적으로 설정해야합니다. -
메소드가 비동기 인 경우을 사용할 수 있습니다
await (Task) obj.InvokeMethod(…)
.
답변
상속을 통해 이것이 불가능하다는 것을 절대적으로 확신하십니까? 리플렉션은 문제를 해결할 때 가장 마지막으로 고려해야 할 사항이며 리팩토링, 코드 이해 및 자동화 된 분석을 더욱 어렵게 만듭니다.
dynMethod를 재정의하는 DrawItem1, DrawItem2 등의 클래스가 있어야합니다.
답변
특히 개인 회원에 대한 반성이 잘못되었습니다
- 반사는 타입 안전을 깨뜨립니다. 존재하지 않는 (더 이상), 잘못된 매개 변수, 너무 많은 매개 변수, 충분하지 않은 또는 불완전한 순서 (이것은 내가 가장 좋아하는 방법)를 호출하려고 시도 할 수 있습니다. 그런데 반환 유형도 변경 될 수 있습니다.
- 반사가 느립니다.
개인 멤버 리플렉션은 캡슐화 원칙을 위반 하여 코드를 다음에 노출시킵니다.
- 클래스의 내부 동작을 처리해야하므로 코드의 복잡성 이 증가 합니다. 숨겨진 것은 숨겨져 있어야합니다.
- 코드 가 컴파일 되기는 쉽지만 메소드가 이름을 변경하면 실행되지 않습니다.
- 개인 코드는 개인 코드 인 경우 그러한 방식으로 호출되지 않기 때문에 쉽게 깨뜨릴 수 있습니다. 아마도 private 메소드는 호출되기 전에 내부 상태를 기대할 수 있습니다.
어쨌든해야합니까?
타사에 의존하거나 노출되지 않은 API가 필요할 때 약간의 반영이 필요합니다. 일부는 또한 자신이 소유 한 일부 클래스를 테스트하기 위해 사용하지만 테스트를 위해 내부 멤버에 액세스하기 위해 인터페이스를 변경하고 싶지 않습니다.
네가하면 제대로 해
- 깨지기 쉬운 완화 :
중단하기 쉬운 문제를 완화하기 위해 최선의 방법은 지속적인 통합 빌드 등에서 실행되는 단위 테스트에서 테스트하여 잠재적 인 중단을 감지하는 것입니다. 물론 이는 항상 동일한 멤버 (개인 멤버를 포함)를 사용한다는 것을 의미합니다. 동적로드 및 리플렉션을 사용하는 경우 화재로 플레이하는 것을 좋아하지만 항상 호출에서 발생할 수있는 예외를 잡을 수 있습니다.
- 반사의 느림을 완화하십시오.
최신 버전의 .Net Framework에서 CreateDelegate는 MethodInfo가 호출하는 요소 50을 이겼습니다.
// The following should be done once since this does some reflection
var method = this.GetType().GetMethod("Draw_" + itemType,
BindingFlags.NonPublic | BindingFlags.Instance);
// Here we create a Func that targets the instance of type which has the
// Draw_ItemType method
var draw = (Func<TInput, Output[]>)_method.CreateDelegate(
typeof(Func<TInput, TOutput[]>), this);
draw
다음 과 같은 표준으로 MethodInfo.Invoke
사용 draw
하는 것보다 약 50 배 빠릅니다 Func
.
var res = draw(methodParams);
다른 메소드 호출에 대한 벤치 마크를 보려면 내 게시물을 확인하십시오.
답변
그리려는 각 유형마다 다른 Draw 방법을 사용할 수 있습니까? 그런 다음 그려 질 itemType 유형의 객체를 전달하는 오버로드 된 Draw 메소드를 호출하십시오.
귀하의 질문에 itemType이 실제로 다른 유형의 객체를 참조하는지 여부가 명확하지 않습니다.