Почему динамический вызов метода не срабатывает, когда отражение все еще работает?

Почему объект dynamic не может вызвать эти методы в объекте COM-объекта NameTranslate при отражении?

Ошибка при использовании динамического:

Type ntt = Type.GetTypeFromProgID("NameTranslate");
dynamic nto = Activator.CreateInstance(ntt);
nto.Init(3,null)

Третья строка выходит из строя с NotImplementedException и сообщением. Метод или операция не реализованы.

Аналогичная попытка, которая работает с использованием другого COM-объекта (WScript.Shell и SendKeys):

Type shellType = Type.GetTypeFromProgID("WScript.Shell");
dynamic shell = Activator.CreateInstance(shellType);
shell.SendKeys("abc");

Возвращение к первому образцу. Если я использую отражение и вызывать методы, используя метод InvokeMethod, все работает нормально.

Рабочий пример с использованием отражения:

Type ntt = Type.GetTypeFromProgID("NameTranslate");
object nto = Activator.CreateInstance(ntt);
object[] initParams = new object[]{3,null};
ntt.InvokeMember("Init", BindingFlags.InvokeMethod, null, nto, initParams);

Я считаю, что это должно иметь какое-то отношение к тому, как создается или помечен COM-объект, но для жизни я ничего не вижу в документах, браузерах объектов или реестре, которые указывают эти COM-объекты и их подсистемы/функции отмечены как частные, так и другие, которые обычно отбрасывают ключевое слово dynamic.

Документация NameTranslate на MSDN: http://msdn.microsoft.com/en-us/library/windows/desktop/aa706046.aspx

Ответ 1

Интересно, что ни один из методов NameTranslate не может быть вызван через dynamic. У меня есть только теоретическое объяснение этого ниже.

AFAIK, когда .NET DLR имеет дело с объектами COM для вызова dynamic, он пытается использовать библиотеку типа COM, если она доступна, а затем прибегает к IDispatch. То, как оно отличается от Reflection, которое сразу же вызывает IDispatch при использовании с COM-объектами.

Библиотека типа ActiveDS (C:\Windows\System32\activeds.tlb), если смотреть с OleView, выглядит несколько плохо сформированной. Он включает в себя множество деклараций, не совместимых с автоматизацией, включая интерфейсы:

interface IPrivateDispatch;
interface ITypeInfo;
interface ITypeComp;
interface ITypeLib;
interface IPrivateUnknown;

Определение класса для NameTranslate себя выглядит следующим образом:

[
  uuid(274FAE1F-3626-11D1-A3A4-00C04FB950DC)
]
coclass NameTranslate {
    [default] interface IADsNameTranslate;
    interface IDispatch;
};

Необязательно (хотя и не запрещено) объявлять IDispatch внутри coclass.

Итак, я бы предположил, что такая библиотека типов и/или coclass определение может запутать DLR в этом случае.

В качестве обходного пути вы можете импортировать его с помощью TlbImp.exe activeds.tlb (что создаст кучу предупреждений), добавьте сборку промежуточных результатов в ваш проект и вызовите API напрямую. Это работает:

Type ntt = Type.GetTypeFromProgID("NameTranslate");
var nto = Activator.CreateInstance(ntt) as ActiveDs.IADsNameTranslate;
nto.Init(3, null);