2012-12-05 4 views
18

C#의 모든 객체에서 정적으로 정의 된 (정적으로 "컴파일 타임에 결정됨"의 의미로 "클래스 수준 멤버"의 의미가 아닌) 메서드를 호출하려는 경우 사용할 수 있습니다. 반사는 방법에 대한 핸들을 얻고 그것을 호출 할 : DynamicObject 응답에서 상속하여 객체를 동적으로 설정,동적 객체에서 메서드를 동적으로 호출하려면 어떻게해야합니까?

typeof(Foo).GetMethod("Bar").Invoke(foo, new object[] { /* params */ }); 

를 단에 (정의되지 않은) 인스턴스 방법은 TryInvokeMember를 사용하여 호출하고 역동적 인 방법은 클래스가 노출되지 않습니다에 응답 명백한 이유 때문에 반사를 통해. 즉, TryInvokeMember에 응답해야하는 메서드에 대한 메서드 핸들을 얻을 수 없다는 의미입니다.

역설적이게도 dynamic 개체에서 정의 된 메서드를 호출 할 수있는 것처럼 쉽게 동적 메서드를 dynamic 개체에서 동적으로 호출 할 수없는 것처럼 보입니다.

나는 TryInvokeMember을 직접 호출하는 것으로 생각했지만 첫 번째 인수는 추상 클래스 인 InvokeMemberBinder의 인스턴스 여야합니다. 나는 동적 객체에서 동적 메소드를 호출하기 위해 클래스를 구현해야한다면, 나는 틀린 일을해야만한다고 생각한다.

어떻게 대상 클래스가 그것을 구현하지 않는 것을 알고, 그 이름하여 dynamic 객체의 메소드를 호출 할 수 있으며이 TryInvokeMember를 사용하여 응답해야한다고?

답변

9

동적 객체의 메서드 호출에 대해 C# 컴파일러가 출력하는 내용을 모방하는 것이 하나의 방법입니다. 이 경우 Microsoft.CSharp.RuntimeBinder 네임 스페이스에 [EditorBrowsable(EditorBrowsableState.Never)]으로 표시된 일련의 유형을 사용해야하므로 Intellisense에 표시되지 않습니다. 말할 필요도없이, 이것은 지원되는 시나리오처럼 보이지 않으므로, 당신의 책임하에 그것을 사용하십시오!

dynamic dynamicObject = new DerivedFromDynamicObject(); 
var callSiteBinder = Binder.InvokeMember(CSharpBinderFlags.None, "Bar", Enumerable.Empty<Type>(), typeof(Program), 
    new[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) }); 
var callSite = CallSite<Action<CallSite, object>>.Create(callSiteBinder); 
callSite.Target(callSite, dynamicObject); 

This 블로그 게시물과 this one 통화 사이트와 바인더에 대한 자세한 피투성이 세부 사항이 있습니다

이 코드는 DynamicObject에서 파생 된 클래스의 인스턴스에 인수없이 동적 Bar 메소드를 호출합니다.

+0

재미 있습니다. 나는 누군가가 실제로 지원되는 해결책을 가지고 있는지보기를 기다릴 것이다. 아마도 이것이 작동을 멈추었을 때 나는 더이상 돌아 가지 않을 것이기 때문이다. – zneak

+1

한편 컴파일러가 이미 수행하고있는 작업이기 때문에 작업을 중단하는 것은 거의 불가능합니다. 이는 현재 구축 된 '동적'을 사용하는 모든 응용 프로그램을 중지시킬 수 있기 때문입니다. – zneak

+0

@zneak 맞아, 나는 그것이 꽤 안전한 내기라고 생각할 것이다. 유형이 숨겨 지도록 할만큼 큰 길을 갔다는 것은 놀라운 일입니다. – Trillian

14

동적 바인더 코드를 캡슐화하는 오픈 소스 (Apache 라이센스) 프레임 워크 Dynamitey (Nuget에서 사용 가능)가 있습니다. 여기에는 자동으로 호출 사이트 캐싱이 포함됩니다. 모든 바인더 유형 (getter, setters, events, indexers, operators, conversions)에 대해 편리한 메소드가 있지만 특히 InvokeMember이 필요합니다.

클래스의 정적으로 정의 된 (컴파일 타임에) 멤버를 호출 할 때 실제로 동적 바인더 코드가 리플렉션 (amortized)보다 빠르게 실행됩니다.

Dynamic.InvokeMember(foo,"Bar",arg...); 
+0

정말 멋지다! – zneak

+0

남자! 위대한 너겟! 완벽하게 작동합니다! 감사합니다. 대답으로 표시해야합니다! – CodeHacker

+0

좋은 패키지, 일을 끝내자. – Andro