Dynamic vs Typed produces strange results
I have SAP RPC OCX control that I'd like to use. In C# 4 following code works fine:
System.Type t = System.Type.GetTypeFromProgID("SAP.Functions", tru开发者_运维知识库e);
dynamic fc = System.Activator.CreateInstance(t, false);
dynamic connection = fc.Connection;
connection.System = "";
Following code does NOT work (even though connection is NOT 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 = "";
Following error is thrown: "Attempted to read or write protected memory. This is often an indication that other memory is corrupt."
The most bizarre fact is this though:
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 = "";
Last line is executed and throws the same exception!!! Replace c2 with c1 works as expected...
I feel I am missing something trivial and yet I am at a complete loss... Please help?
Additional info: Changing from:
dynamic fc = System.Activator.CreateInstance(t, false);
to:
var fc = System.Activator.CreateInstance(t, false) as SAPFunctionsOCX.SAPFunctions;
Makes no difference. c1 still works and c2 still does not.
Additional info #2: Changing properties on FC itself also works in both cases.
Although it looks like you're doing the same thing both times, it's actually completely different: In the first code example:
dynamic connection = fc.Connection;
connection.System = "";
what happens is you get fc.Connection
, and then invoke the System =
property setter using dynamic
. The dynamic language runtime goes off and queries the COM interfaces, and invokes a particular method on a particular COM interface. You can't actually see what interface or method it's using from the C# side of things.
In the second example (I've replaced the var
to make things more clear):
SAPLogonCtrl.Connection connection = fc.Connection as SAPLogonCtrl.Connection
connection.System = "";
what happens is you get fc.Connection
, and then cast it to SAPLogonCtrl.Connection
. You then try and call SAPLogonCtrl.Connection.System =
and then it fails.
I suspect that it's failing because the object is not actually an instance of SAPLogonCtrl.Connection
but it may be a proxy or some other object.
Most COM interop is split into an interface (there's most likely an SAPLogonCtrl.IConnection
) and a class. When calling methods, you usually need to call through the interface. The dynamic
code will be doing it all for you behind the scenes.
You could try searching for the interface, and calling using that. If it ends up that SAPLogonCtrl.IConnection
exists, the solution may be as follows.
var connection = fc.Connection as SAPLogonCtrl.IConnection // note the I!
connection.System = "";
At any rate, remember to call through the interface when dealing with COM interop
Can you not just add the actual control as a reference to your project and use it through the interop code Visual Studio creates, instead of trying to create it through COM and reflection?
Just an idea but since dynamic is not bound until execution time, whereas var is bound at compile time, could it be that the type of fc isn't available to connection?
EDIT: As a side issue, is there any need to use:
var connection = fc.Connection as SAPLogonCtrl.Connection
Where you could just use:
SAPLogonCtrl.Connection connection = fc.Connection;
Am I missing something? Why would you set it as an implicit type and then explicitly cast it?
You have to realize at runtime Dynamic runs as an Object and Object can accept anything. This simple fact is pointed out in Beginning C# 4.0
Note Unusually, the dynamic type only exists at compile time; at runtime the System.Object type is used instead. This is a minor implementation detail but one that is worth remembering, as it may clarify some of the discussion that follows. Once you have a dynamic variable, you can proceed to access its members (the code to actually obtain a value for the variable is not shown here): myDynamicVar.DoSomething(“With this!”);
Watson, Karli; Nagel, Christian; Pedersen, Jacob Hammer; Reid, Jon D.; Skinner, Morgan (2011-02-08). Beginning Visual C# 2010 (Wrox Programmer to Programmer) (p. 414). Wrox. Kindle Edition.
精彩评论