Hi everyone i had a issue with a code in C# .NET, I'm using a DLL for connect to OPC Servers the DLL that was used in a VB.NET project and works with no problem at all.
I'm trying to show a list of available Servers in a ListBox, the code used in VB.NET (and works) is this one:
Dim AllOPCServers As Object
AllOPCServers = AnOPCServer.GetOPCServers
' Load the list returned into the List box for user selection
Dim i As Short
For i = LBound(AllOPCServers) To UBound(AllOPCServers)
AvailableOPCServerList.Items.Add(AllOPCServers(i))
Next i
and i wrote this to use in the C# application
try
{
var _listOPCServer = _OPCServer.GetOPCServers();
foreach(var i in _listOPCServer)
{
string serverName = (string)i;
listServers.Items.Add(serverName);
}
}
catch (Exception exc)
{
lstMsg.Items.Add(DateTime.Now + " Error al Obtener Lista de OPC's: " + exc.Message);
}
On Debug mode on Local tab shows this:
_listOPCServer | {string[1..2]} | dynamic {string[]} |
[1] | "Server01" | string
[2] | "Server02" | string
UPDATE:
I get the error in line "foreach(var i in _listOPCServer)"
Unable To Cast object type 'System.String[*]' to type 'System.String[]'
That is the actually error.
I'm sure that I'm doing something wrong, can someone help me?
Ok i found a way to work this out and it's only a mod of your advices
Array _listOPCServer = (Array)(object)_OPCServer.GetOPCServers();
foreach(object i in _listOPCServer)
{
string serverName = (string)i;
listServers.Items.Add(serverName);
}
I only added (object) in the declaration and works fine, now i can show the list of servers just the way i wanted it
or also do this
Array _listOPCServer = (Array)(object)_OPCServer.GetOPCServers();
foreach(object i in _listOPCServer)
{
listServers.Items.Add(i);
}
Again, thanks a lot for your help and time!
VB.NET is a lot more astute at dealing with non-conforming array types. Don't hesitate to use it, .NET make it easy to have languages inter-operate with each other.
At issue is that OPC is a COM based standard. The server you are using is returning a SAFEARRAY with a non-conforming lower bound, the first index is 1. Not 0. Not that unusual in COM, choosing between 0 and 1 as the first array index is like the endian problem or arguing whether a tomato is a fruit or a vegetable (It is a fruit. And little-endian is the right kind of vegetable).
However, 0 as the lower bound is what C# insists on when dealing with one-dimensional arrays. It wants a "vector", a distinct array type that always has one dimension with a lower bound of 0. Heavily optimized in the .NET runtime. What you get back doesn't match so is mapped to a multi-dimensional array with one dimension. Not an array type you can express in the C# language.
You can hack it in C#, but you'll have to use the Array type explicitly. Something like this, spelled out for clarity:
Array servers = (Array)_OPCServer.GetOPCServers();
int first = servers.GetLowerBound(0);
int last = servers.GetUpperBound(0);
for (int ix = first; ix <= last; ++ix) {
var elem = (string)servers.GetValue(ix);
// etc..
}
While Hans is correct in distinguishing the difference between a zero-based array and a non-zero-based array, I still don't see why you're getting that exception.
My guess is that you're declaring _OPCServer
as dynamic
, which defers type-binding until run-time. Thus _listOPCServer
is dynamic
as well.
Since you're iterating over the array and extracting string
s, the compiler may be trying to cast the object to a string[]
which as Hans points out is invalid.
You should be able to cast _listOPCServer
to an Array
and use the foreach
just as you are:
Array _listOPCServer = (Array)(_OPCServer.GetOPCServers());
foreach(var i in _listOPCServer)
{
// etc.