无法将对象类型 'System.String[*]' 强制转换为类型 'System.String[]'

4

大家好,我在C# .NET代码中遇到了问题。我正在使用一个DLL连接到OPC服务器,该DLL已经在VB.NET项目中使用并且没有任何问题。

我尝试在一个ListBox中显示可用服务器列表,VB.NET中使用的代码是:

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

我写这个是为了在C#应用程序中使用

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);
}

在本地选项卡上调试模式显示如下:

_listOPCServer | {string[1..2]} | dynamic {string[]} |

[1]        |  "Server01"    | string  
[2]        |  "Server02"    | string

更新:

我在 "foreach(var i in _listOPCServer)" 这一行收到了错误提示。

无法将对象类型 'System.String[*]' 强制转换为类型 'System.String[]'

这是实际的错误提示。

我确定自己做错了什么,能有人帮帮我吗?


1
这里是一个类似情况的最小复现代码:(string[])(new string[0,0]),虽然我不知道如何产生完全相同的消息.. 不过请您发表 真实错误消息 (复制并粘贴)以避免可能出现的错误。 - user166390
你在哪一行遇到了错误?我没有看到你试图将 _listOPCServer 转换为任何类型。 - D Stanley
@pst 这是我得到的错误信息:无法将对象类型 'System.Sting[*]' 强制转换为类型 'System.String[]'。 - Manuel Espino
@DStanley 我在这行代码 foreach(var i in _listOPCServer) 中遇到了错误。 - Manuel Espino
@DStanley 哈哈抱歉,拼错了,应该是String,让我更正一下。 - Manuel Espino
3个回答

5

好的,我找到了一种解决方法,只需要对您的建议进行修改即可。

 Array _listOPCServer = (Array)(object)_OPCServer.GetOPCServers();               

            foreach(object i in _listOPCServer)
            {
                string serverName = (string)i;
                listServers.Items.Add(serverName);
            }             

我只是在声明中添加了(object),现在它可以正常工作,我可以按照自己想要的方式显示服务器列表。

或者也可以这样做:

Array _listOPCServer = (Array)(object)_OPCServer.GetOPCServers();               

            foreach(object i in _listOPCServer)
            {
                listServers.Items.Add(i);
            }

再次感谢您的帮助和时间!

(这段话已经是中文了,无需翻译)

2

VB.NET在处理不符合规范的数组类型方面更加智能。不要犹豫使用它,.NET使语言之间的互操作变得容易。

问题在于OPC是基于COM标准的。您正在使用的服务器返回一个具有非符合性下限的SAFEARRAY,第一个索引为1而不是0。在COM中并不罕见,选择0和1作为第一个数组索引就像端序问题或争论番茄是水果还是蔬菜一样(它是一种水果。小端序是正确的蔬菜)。

然而,在处理一维数组时,C#坚持将0作为下限。它想要一个“向量”,这是一种具有始终具有下限为0的一个维度的不同数组类型。在.NET运行时中进行了大量优化。由于您收到的内容不匹配,因此被映射到具有一个维度的多维数组中。这不是您可以用C#语言表达的数组类型。

您可以在C#中进行修改,但必须明确地使用Array类型。以下是为了清晰起见拼写出来的示例:

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..
}

其实我也不知道。我从来没有想过尝试它,因为数组实现了“IEnumerable<T>”的假象在这种代码中注定会失败。你可以试试看。强制转换很明显,Array.GetValue()返回一个Object。 - Hans Passant
我指的是从 System.Sting[*]System.String[] 的转换,这是 OP 引发异常的原因。 - D Stanley
不,那不可能奏效。我的回答保持不变。向量与具有一个维度的多维数组不兼容。 - Hans Passant
嗨@HansPassant,感谢你抽出时间回答我的问题,但是在我在这里发布问题后,我发现你在这里评论的解释。我还尝试将其声明为Array类型,但在Array servers =(Array)_OPCServer.GetOPCServer行上仍会出现相同的错误。 - Manuel Espino
就像@ManuelEspino所说,错误仍然在服务器变量创建时弹出。在转换为数组之前先转换为对象可以使其像ManuelEspino在他的答案中描述的那样工作。 - Matthieu
显示剩余2条评论

1

虽然Hans在区分基于零和非基于零的数组之间的差异方面是正确的,但我仍然不明白为什么您会遇到该异常。

我猜测您将_OPCServer声明为dynamic,这会推迟类型绑定直到运行时。因此,_listOPCServer也是dynamic

由于您正在遍历数组并提取string,编译器可能会尝试将对象强制转换为string[],正如Hans所指出的那样是无效的。

您应该能够将_listOPCServer转换为Array并像您一样使用foreach

Array _listOPCServer = (Array)(_OPCServer.GetOPCServers());
foreach(var i in _listOPCServer)
{
    // etc.

你好,感谢抽出时间回答这个问题,但是我已经尝试了你推荐的方法,但在代码行 Array _listOPCServer = (Array)(_OPCServer.GetOPCServers()); 仍然遇到了相同的错误。 - Manuel Espino
我得到了相同的错误,我会更新帖子并附上一些截图。 - Manuel Espino

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接