반사를 사용하여 개인 메서드를 호출하려면 어떻게 해야 합니까?
우리 반에는 개인 메소드 그룹이 있는데, 입력 값을 기준으로 동적으로 하나를 호출해야 합니다.호출 코드와 대상 메서드가 모두 동일한 인스턴스에 있습니다.코드는 다음과 같습니다.
MethodInfo dynMethod = this.GetType().GetMethod("Draw_" + itemType);
dynMethod.Invoke(this, new object[] { methodParams });
이경에는우,,GetMethod()
개인 메서드를 반환하지 않습니다.무엇을BindingFlags
가 공해야합까니에 ?GetMethod()
개인적인 방법을 찾을 수 있게요?
BindingFlags를 허용하는 의 오버로드된 버전을 사용하도록 코드를 변경하기만 하면 됩니다.
MethodInfo dynMethod = this.GetType().GetMethod("Draw_" + itemType,
BindingFlags.NonPublic | BindingFlags.Instance);
dynMethod.Invoke(this, new object[] { methodParams });
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 포함)에서 작동해야 합니다.양식 및 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
. superclass유형으로 설정해야 합니다.에는 메드가비경사수있용습다니할우인을 사용할 수 .
await (Task) obj.InvokeMethod(…)
.
특히 개인 회원에 대한 반영이 잘못되었습니다.
- 반사로 인해 형식 안전이 깨집니다.더 이상 존재하지 않거나 잘못된 매개 변수를 사용하거나 매개 변수가 너무 많거나 충분하지 않은 메서드를 호출할 수 있습니다.또는 잘못된 순서로(이것은 내가 가장 좋아하는 것입니다 :).그런데 반품 타입도 변경될 수 있습니다.
- 반사가 느립니다.
개인 멤버 반사는 캡슐화 원리를 위반하여 코드를 다음에 노출시킵니다.
- 클래스의 내부 동작을 처리해야 하므로 코드의 복잡성을 높입니다.숨겨진 것은 숨겨져야 합니다.
- 컴파일할 때 코드를 쉽게 깰 수 있지만 메서드가 이름을 변경하면 실행되지 않습니다.
- 개인 코드는 비공개일 경우 이러한 방식으로 호출되지 않으므로 쉽게 해제할 수 있습니다.아마도 사적인 방법은 호출되기 전에 내부 상태를 예상할 수 있습니다.
어차피 해야 한다면요?
그래서 제3자에게 의존하거나 노출되지 않은 API가 필요할 때는 반성을 해야 합니다.일부는 자신이 소유한 일부 클래스를 테스트하는 데도 사용하지만 테스트를 위해 내부 구성원에게 액세스 권한을 부여하기 위해 인터페이스를 변경하지는 않습니다.
당신이 그것을 한다면, 제대로 하라.
- 깨지기 쉬운 문제 완화:
중단하기 쉬운 문제를 완화하려면 연속적인 통합 빌드 등에서 실행되는 장치 테스트에서 테스트를 수행하여 잠재적인 중단을 감지하는 것이 가장 좋습니다.물론 이는 항상 동일한 어셈블리(개인 구성원 포함)를 사용한다는 의미입니다.동적 부하와 반사를 사용하는 경우 불장난을 좋아하지만 통화에서 발생할 수 있는 예외를 항상 잡을 수 있습니다.
- 반사 속도 완화:
의 최신 버전.NetFramework, 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
는 배화속보약다는 50다니빠보다 약 더 입니다.MethodInfo.Invoke
사용하다draw
Func
그런 식으로:
var res = draw(methodParams);
다양한 메서드 호출에 대한 벤치마크를 보려면 이 게시물을 확인하십시오.
당신은 이것이 상속을 통해 이루어질 수 없다고 확신합니까?성찰은 문제를 해결할 때 가장 마지막으로 살펴봐야 하는 것으로, 리팩터링, 코드 이해 및 자동화된 분석을 더욱 어렵게 만듭니다.
dynMethod를 재정의하는 DrawItem1, DrawItem2 등의 클래스가 있어야 합니다.
개체 인스턴스의 보호 수준에도 불구하고 메서드를 호출합니다.맛있게 드세요!
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);
}
파생 클래스에서 호출하는 것은 문제가 있을 수 있습니다.
오류 발생 가능성:
this.GetType().GetMethod("PrivateTestMethod", BindingFlags.Instance | BindingFlags.NonPublic)
정답:
typeof(CurrentClass).GetMethod("PrivateTestMethod", BindingFlags.Instance | BindingFlags.NonPublic)
당신은 통과할 수 있을 것 같아요.BindingFlags.NonPublic
그것이 있는 곳에GetMethod
방법.
그리고자 하는 유형별로 다른 그리기 방법을 사용할 수는 없습니까?그런 다음 오버로드된 그리기 메서드를 호출하여 유형 항목의 개체를 전달합니다.그릴 유형입니다.
당신의 질문은 품목이 확실하지 않습니다.유형은 실제로 서로 다른 유형의 개체를 나타냅니다.
이 (보조) 답변(때로는 정답)을 읽고 이 내용이 어디로 가고 있는지, 그리고 이 스레드에 있는 일부 사람들이 "아직도 작동하지 않는다"고 불평하는 이유를 이해하십시오.
저는 여기 답 중 하나와 정확히 같은 코드를 작성했습니다.하지만 저는 여전히 문제가 있었습니다.중단점을 두었습니다.
var mi = o.GetType().GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance );
실행은 했지만,mi == null
그리고 제가 관련된 모든 프로젝트에 대해 "재구축"을 할 때까지 이런 행동을 계속했습니다.저는 반사 방법이 세 번째 어셈블리에 앉아 있는 동안 한 어셈블리를 유닛 테스트하고 있었습니다.완전히 혼란스러웠지만 즉시 창을 사용하여 메소드를 검색해 보니 테스트를 단위화하려고 시도한 개인 메소드의 이름이 이전 이름(이름 변경)이었습니다.이것은 유닛 테스트 프로젝트가 구축되더라도 오래된 어셈블리 또는 PDB가 여전히 존재한다는 것을 알려주었습니다. 어떤 이유에서인지 테스트가 구축되지 않았습니다."일"이 작동했습니다.
언급URL : https://stackoverflow.com/questions/135443/how-do-i-use-reflection-to-invoke-a-private-method
'code' 카테고리의 다른 글
오류: Android Studio의 SDK에서 adb를 찾을 수 없습니다. (0) | 2023.05.28 |
---|---|
Eclipse에서 TODO/FIXME/XXX 작업 태그를 활성화하려면 어떻게 해야 합니까? (0) | 2023.05.28 |
Json.net 을 사용하여 JSON 개체를 동적 개체로 역직렬화 (0) | 2023.05.28 |
왜 저는 캐치 없이 시도만 하거나 마지막으로 글을 쓸 수 없습니까? (0) | 2023.05.28 |
Android 보기에서 자주 발생하는 문제, XML 구문 분석 오류: 바인딩되지 않은 접두사 (0) | 2023.05.28 |