Как использовать отражение на COM-объекте, доступном через RCW? - PullRequest
0 голосов
/ 18 июня 2020

Я использовал средство импорта библиотеки типов (TlbImp.exe) для создания сборки взаимодействия для взаимодействия с COM-объектом. Я пытаюсь построить дерево выражений, которое вызывает метод COM-объекта. Я хочу скомпилировать дерево выражения в лямбду и кэшировать его.

Причина, по которой я хочу это сделать, состоит в том, что в этом COM-объекте есть много похожих интерфейсов, в которых изменяется только тип параметра. Например, есть интерфейс для IFooDouble, IFooInt, IFooString, IFooLongInt, et c. Затем каждый из них будет определять метод SetValue (значение T), где T будет либо double, int, string, et c., В зависимости от интерфейса. Здесь я бы скомпилировал дерево выражений в лямбду Action<IFooBase, T> и кэшировал бы его.

Сгенерированная сборка взаимодействия содержит строго типизированные интерфейсы для метода SetValue, но я не могу найти способ получить ссылку на него MethodInfo объект через отражение. Поскольку тип оболочки - System.__ComObject, я могу вызвать InvokeMember и сделать это таким же образом. Однако мне интересно, будет ли это намного медленнее, чем если бы я вызвал метод напрямую через один из интерфейсов взаимодействия? То есть мне интересно, будет ли IFooBase.InvokeMember("SetValue", ...) иметь гораздо худшую производительность, чем IFooDouble.SetValue(11.3), особенно при выполнении большого количества повторных вызовов.

1 Ответ

0 голосов
/ 19 июня 2020

Я смог заставить это работать после некоторых экспериментов в одноразовом консольном приложении. Оказывается, я сделал несколько ошибок в вызовах рефлексии. Я не использовал полное имя типа интерфейса, включая пространство имен, в методе Assembly.GetType. Я также не указал правильные флаги в BindingFlags аргументе Type.GetMethod.

Вот его рабочая версия:

private static Action<object, T> CreateSetterExpression<T>(string fooType)
{
    // IFoo is a base interface in the interop assembly that
    // we are interested in.
    var fooBaseInterfaceType = typeof(IFoo);
    var fooInterfaceType = fooBaseInterfaceType.Assembly
        .GetType(
            $"{fooBaseInterfaceType.Namespace}.IFoo{fooType}",
            true,
            true);

    var setValueMethodInfo = fooInterfaceType.GetMethod("SetRequestedValue",
        BindingFlags.Instance | BindingFlags.Public,
        null,
        CallingConventions.Any,
        new[] { typeof(T) },
        null);

    ParameterExpression instanceParam = Expression.Parameter(typeof(object), "instanceObject");
    var instanceExp = Expression.Convert(instanceParam, fooInterfaceType);

    ParameterExpression valueParam = Expression.Parameter(typeof(T), "value");

    var callExpression = Expression.Call(instanceExp, setValueMethodInfo, valueParam);

    return Expression.Lambda<Action<object, T>>(
            callExpression, instanceParam, valueParam)
        .Compile();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...