리플렉션을 사용하여 개인 메서드를 호출하려면 어떻게합니까?
내 클래스에는 개인 메소드 그룹이 있으며 입력 값을 기반으로 동적 메소드를 호출해야합니다. 호출 코드와 대상 메소드는 모두 동일한 인스턴스에 있습니다. 코드는 다음과 같습니다.
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이 실제로 다른 유형의 객체를 참조하는지 여부가 명확하지 않습니다.
나는 당신이 그것을 전달할 수 있다고 생각 BindingFlags.NonPublic
곳 이 는 IS GetMethod
방법.
개체 인스턴스의 보호 수준에도 불구하고 모든 메서드를 호출합니다. 즐겨!
public static object InvokeMethod(object obj, string methodName, params object[] methodParams)
{
var methodParamTypes = methodParams?.Select(p => p.GetType()).ToArray() ?? new Type[] { };
var bindingFlags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static;
MethodInfo method = null;
var type = obj.GetType();
while (method == null && type != null)
{
method = type.GetMethod(methodName, bindingFlags, Type.DefaultBinder, methodParamTypes, null);
type = type.BaseType;
}
return method?.Invoke(obj, methodParams);
}
이 (보완적인) 대답 (때로는 대답)을 읽고 이것이 어디로 가고 있으며이 스레드의 일부 사람들이 왜 여전히 작동하지 않는다고 불평 하는지 이해하십시오.
나는 여기에 대한 답변 중 하나와 정확히 동일한 코드를 작성했습니다 . 그러나 여전히 문제가 있습니다. 나는 브레이크 포인트를
var mi = o.GetType().GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance );
실행되었지만 mi == null
그리고 관련된 모든 프로젝트에서 "재 구축"할 때까지 이와 같은 동작이 계속되었습니다. 반사 방법이 세 번째 어셈블리에 앉아있는 동안 하나의 어셈블리를 단위 테스트했습니다. 완전히 혼란 스럽지만 Immediate Window를 사용하여 메소드를 발견했으며 단위 테스트를 시도한 개인 메소드의 이름이 이전이라는 것을 알았습니다. 이것은 단위 테스트 프로젝트가 빌드 된 경우에도 이전 어셈블리 또는 PDB가 여전히 존재한다고 말했습니다. 어떤 이유로 테스트하지 않은 프로젝트입니다. "재건축"
BindingFlags.NonPublic
참고 URL : https://stackoverflow.com/questions/135443/how-do-i-use-reflection-to-invoke-a-private-method
'Programing' 카테고리의 다른 글
파이썬에서 줄 바꿈없이 파일 읽기 (0) | 2020.03.12 |
---|---|
IDENTITY_INSERT가 OFF로 설정된 경우 'table'테이블에서 ID 열에 명시 적 값을 삽입 할 수 없습니다. (0) | 2020.03.12 |
enumerate ()는 무엇을 의미합니까? (0) | 2020.03.12 |
파이썬에서 순환 (또는 순환) 가져 오기 (0) | 2020.03.12 |
루프 전 또는 루프에서 변수 선언의 차이점은 무엇입니까? (0) | 2020.03.12 |