Dynamic vs Typed会产生奇怪的结果

时间:2011-05-26 14:26:49

标签: 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 = "";

以下代码不起作用(即使连接非空)

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 = "";

抛出以下错误: “试图读取或写入受保护的内存。这通常表明其他内存已损坏。”

最奇怪的事实是:

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 = "";

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

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

其他信息: 改变自:

dynamic fc = System.Activator.CreateInstance(t, false);

为:

var fc = System.Activator.CreateInstance(t, false) as SAPFunctionsOCX.SAPFunctions;

没有任何区别。 c1仍然有效,而c2仍然没有。

其他信息#2: 更改FC本身的属性也适用于这两种情况。

4 个答案:

答案 0 :(得分:1)

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

dynamic connection = fc.Connection;
connection.System = "";

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

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

SAPLogonCtrl.Connection connection = fc.Connection as SAPLogonCtrl.Connection
connection.System = "";

如果您获得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 = "";

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

答案 1 :(得分:0)

您是否可以将实际控件添加为项目的引用并通过Visual Studio创建的互操作代码使用它,而不是尝试通过COM和反射创建它?

答案 2 :(得分:0)

只是一个想法,但由于动态直到执行时才被绑定,而var在编译时被绑定,可能是fc的类型不可用于连接吗?

编辑:作为一个副作用,是否有任何需要使用:

var connection = fc.Connection as SAPLogonCtrl.Connection

您可以使用的地方:

SAPLogonCtrl.Connection connection = fc.Connection;

我错过了什么吗?为什么要将它设置为隐式类型然后显式地转换它?

答案 3 :(得分:0)

你必须在运行时实现动态运行作为对象和对象可以接受任何东西。这个简单的事实在Beginning C#4.0

中指出
  

注意不同寻常,动态类型仅在编译时存在;在运行时,使用System.Object类型。这是一个次要的实现细节,但值得记住,因为它可能会澄清下面的一些讨论。一旦你有了一个动态变量,就可以继续访问它的成员了(这里没有显示实际获取变量值的代码):myDynamicVar.DoSomething(“With this!”);

Watson,Karli; Nagel,Christian;佩德森,雅各布汉默; Reid,Jon D。;斯金纳,摩根(2011-02-08)。从Visual C#2010开始(Wrox程序员到程序员)(p.414)。 Wrox的。 Kindle版。