Подтвердить что ты не робот

Как я могу динамически вызывать метод для динамического объекта?

Когда я хочу динамически вызывать статически определенный ( "статически" в смысле "определенный во время компиляции", а не в смысле метода "класс-член" ) для любого объекта в С#, я могу используйте отражение, чтобы получить дескриптор этого метода и вызвать его:

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

Однако объекты, сделанные динамическими, наследуя от DynamicObject, реагируют на вызовы метода экземпляра (undefined) с использованием TryInvokeMember, а динамические методы, на которые отвечает класс, не могут быть обнаружены посредством отражения по очевидным причинам. Это означает, что я не могу получить дескриптор метода для метода, на который должен отвечать TryInvokeMember.

Как ни странно, мне кажется, что вы не можете динамически вызывать динамический метод для объекта dynamic так же легко, как вы можете вызвать определенный метод для объекта dynamic.

Я рассмотрел вызов TryInvokeMember напрямую, но первым аргументом должен быть экземпляр InvokeMemberBinder, абстрактного класса. Я чувствую, что если мне нужно реализовать класс для вызова динамического метода для динамического объекта, я должен делать что-то неправильно.

Как я могу вызвать метод в объекте dynamic по его имени, зная, что целевой класс не реализует его и что он должен отвечать на использование TryInvokeMember?

4b9b3361

Ответ 1

Один из способов сделать это - подражать тому, что компилятор С# выводит для вызова метода для динамических объектов. Для этого требуется использование нескольких типов с меткой [EditorBrowsable(EditorBrowsableState.Never)] в пространстве имен Microsoft.CSharp.RuntimeBinder, поэтому они не будут видны в Intellisense. Излишне говорить, что это не похоже на поддерживаемый сценарий, поэтому используйте его на свой страх и риск!

Этот код вызывает динамический Bar метод без каких-либо аргументов в экземпляре класса, полученного из DynamicObject:

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);

Это сообщение в блоге и этот имеет больше gory сведения о сайтах и ​​связующих сайтах.

Ответ 2

У меня есть версия с открытым исходным кодом (лицензия Apache) Dynamitey (доступна в nuget), которая инкапсулирует динамический код связующего, это включает в себя автоматическое кэширование сайтов вызовов. Он также имеет удобные методы для каждого типа связующего (геттеры, сеттеры, события, индексы, операторы, конверсии), но специально вы хотите InvokeMember.

Динамический код связующего на самом деле работает быстрее, чем отражение (амортизируется) при вызове статически определенных (во время компиляции) элементов классов.

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