[C#] 리플렉션을 사용하여 개인 메서드를 호출하려면 어떻게합니까?

내 클래스에는 개인 메소드 그룹이 있으며 입력 값을 기반으로 동적 메소드를 호출해야합니다. 호출 코드와 대상 메소드는 모두 동일한 인스턴스에 있습니다. 코드는 다음과 같습니다.

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이 실제로 다른 유형의 객체를 참조하는지 여부가 명확하지 않습니다.