Dynamic vs Typed会产生奇怪的结果

Mic*_*ein 7 c# interop

我有SAP RPC OCX控件,我想使用它.在C#4下面的代码工作正常:

System.Type t = System.Type.GetTypeFromProgID("SAP.Functions", true);            
dynamic fc = System.Activator.CreateInstance(t, false);
dynamic connection = fc.Connection;
connection.System = "";
Run Code Online (Sandbox Code Playgroud)

以下代码不起作用(即使连接不为null)

System.Type t = System.Type.GetTypeFromProgID("SAP.Functions", true);            
dynamic fc = System.Activator.CreateInstance(t, false);
var connection = fc.Connection as SAPLogonCtrl.Connection
connection.System = "";
Run Code Online (Sandbox Code Playgroud)

抛出以下错误:"尝试读取或写入受保护的内存.这通常表示其他内存已损坏."

最奇怪的事实是:

System.Type t = System.Type.GetTypeFromProgID("SAP.Functions", true);            
dynamic fc = System.Activator.CreateInstance(t, false);
dynamic c1 = fc.Connection;
var c2 = fc.Connection as SAPLogonCtrl.Connection;
if (c1 == c2)
  c2.System = "";
Run Code Online (Sandbox Code Playgroud)

最后一行被执行并抛出相同的异常!用c1替换c2按预期工作...

我觉得我错过了一些微不足道的事情,但我完全失去了...请帮帮忙?

其他信息:改变自:

dynamic fc = System.Activator.CreateInstance(t, false);
Run Code Online (Sandbox Code Playgroud)

至:

var fc = System.Activator.CreateInstance(t, false) as SAPFunctionsOCX.SAPFunctions;
Run Code Online (Sandbox Code Playgroud)

没有区别.c1仍然有效,而c2仍然没有.

附加信息#2:改变FC本身的属性也适用于这两种情况.

Ori*_*rds 1

虽然看起来两次都在做同样的事情,但实际上完全不同:在第一个代码示例中:

dynamic connection = fc.Connection;
connection.System = "";
Run Code Online (Sandbox Code Playgroud)

发生的情况是您得到fc.Connection,然后System =使用 调用属性设置器dynamic。动态语言运行时启动并查询 COM 接口,并调用特定 COM 接口上的特定方法。您实际上无法从 C# 方面看到它正在使用什么接口或方法。

在第二个示例中(我已经替换了var以使事情更清楚):

SAPLogonCtrl.Connection connection = fc.Connection as SAPLogonCtrl.Connection
connection.System = "";
Run Code Online (Sandbox Code Playgroud)

发生的事情是你得到fc.Connection,然后将其投射到SAPLogonCtrl.Connection. 然后你尝试打电话SAPLogonCtrl.Connection.System =,但失败了。

我怀疑它失败了,因为该对象实际上并不是 的实例,SAPLogonCtrl.Connection但它可能是代理或其他对象。

大多数 COM 互操作都分为接口(很可能是一个SAPLogonCtrl.IConnection)和类。调用方法时,通常需要通过接口来调用。该dynamic代码将在幕后为您完成这一切。

您可以尝试搜索该接口,然后使用该接口进行调用。如果最终存在SAPLogonCtrl.IConnection,解决方案可能如下。

var connection = fc.Connection as SAPLogonCtrl.IConnection // note the I!
connection.System = "";
Run Code Online (Sandbox Code Playgroud)

无论如何,在处理 COM 互操作时记得通过接口调用