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

Как вызвать DynamicObject.TryGetMember напрямую?

Я реализую функцию общего назначения для извлечения значения из произвольного предоставленного динамического объекта, но не знаю, как вызвать TryGetMember, потому что для него требуется GetMemberBinder, который является абстрактным, поэтому я не могу его создать. Пример...

public object GetValue(DynamicObject Source, string FieldName)
{
    object Result = null;
    GetMemberBinder Binder = x;  // What object must be provided?
    Binder.Name = FieldName;
    if (Source.TryGetMember(Binder, out Result))
       return Result;

    throw new Exception("The field '" + FieldName + "' not exists");
}

Есть ли уже существующий конкретный потомок GetMemberBinder, готовый к использованию? или руководство для создания моей собственной реализации?

4b9b3361

Ответ 1

Я не уверен, есть ли какой-либо метод в структуре, который фактически возвращает GetMemberBinder, но это не имеет значения - это не правильный способ вызвать динамический член по имени.

Что вам действительно нужно сделать, так это создать сайт вызова. Метод выглядит следующим образом:

static object GetDynamicMember(object obj, string memberName)
{
    var binder = Binder.GetMember(CSharpBinderFlags.None, memberName, obj.GetType(),
        new[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) });
    var callsite = CallSite<Func<CallSite, object, object>>.Create(binder);
    return callsite.Target(callsite, obj);
}

Обратите внимание, что Binder.GetMember создает CallSiteBinder, не a GetMemberBinder. Просто чтобы быть на 100% ясным. Этот метод выдает RuntimeBinderException, если внутренний вызов TryGetMember завершается с ошибкой, поэтому вам не нужно проверять результат. Если вы не хотите, чтобы вызывающие абоненты увидели RuntimeBinderException, затем заверните его в свой собственный try/catch.

Динамическая отправка сложна, по крайней мере, относительно отражения на статических типах. Поскольку CLR на самом деле не динамически типизирован, С# должен фактически создать экземпляр компилятора, чтобы выяснить, как выполнить элемент/метод. Это создание сайта вызова. Насколько мне известно, вы должны это сделать, поэтому каждый метод Binder возвращает CallSiteBinder, и вы не можете напрямую создавать какие-либо связующие.

Обратите внимание, что DLR выполняет какое-то кэширование сайта вызова, но я не уверен, что автоматическое кэширование охватывает этот сценарий. Там есть хорошая вероятность, что вы захотите сохранить свой сайт для будущих вызовов, чтобы избежать накладных расходов на постоянную перекомпиляцию.

P.S. Если вы используете (или можете использовать) ExpandoObject вместо DynamicObject, то имейте в виду, что он реализует IDictionary<string, object>, поэтому вам не нужно ничего делать. Просто введите его в тип словаря и проверьте, существует ли свойство. Я бы использовал только DynamicObject над ExpandoObject, если бы я делал что-то намного сложнее, чем просто добавлять элементы во время выполнения, т.е. Изменяя фактическое поведение на основе связующего времени выполнения.

Ответ 2

Вы не вызываете TryGetMember напрямую, вам нужно использовать динамический api напрямую, чтобы получить тот же эффект с помощью связующего элемента csharp и сайта вызова.

Это делается еще проще с помощью фреймворка с открытым исходным кодом Dynamitey (через nuget), поскольку он имеет статический метод, который делает это. Он работает для любого IDynamicMetaObjectProvider не только DynamicObject и (он работает для обычных типов быстрее, чем отражение тоже).

return Dynamic.InvokeGet(Source, FieldName);