What is a String[*] and how do I cast it?

2019-02-25 13:12发布

问题:

I'm currently in the unfortunate position of having to call a VBA macro from C#, via the COM Interop. The macro returns an array of strings and looks something like:

Public Function Foo() As String()

which I'm then trying to cast to an array of strings in C# like this:

var result = (string[])xlApp.Run("Foo", ... missing args ...)

which then results in the runtime error:

Unable to cast object of type 'System.String[*]' to type 'System.String[]'.

Does anyone know what a String[*] is, and do you have any idea of how to cast it to a C# string[]? This cast works in a simple test case I've created. The only difference I can see, is that in the simple case, my array in VBA is of type string(0 to 5) whereas in the more complex case, it's of type string(1 to 6). Could this be the reason and if so, my VBA is rather rusty - how do I fix it?

Many thanks,
Jon

回答1:

Your code was

var result = (string[])xlApp.Run("Foo", ... missing args ...);

As you have pointed out there is different behaviour with a 1-based array, with a zero-based array in VB your code does work.

You can get at the data like this

var result = (Array)xlApp.Run("Foo", ... missing args ...);

var stringsResult = result.Cast<string>[];

This gives you an IEnumerable of string



回答2:

.NET supports such arrays (that have lower bound different from 0), you can create one using such snippet:

Array arr = Array.CreateInstance(typeof(string), new int[] { 5 }, new int[] {1});

The simplest way to convert such array to string[] is (although, it's copying data, on the other hands, those are just references, so if your arrays aren't too long, you won't get huge perf hit):

string[] x = new string[5];
Array.Copy(arr, 1, x, 0, 5);

Edit: Or using more general approach:

string[] x = new string[arr.GetLength(0)];
Array.Copy(arr, arr.GetLowerBound(0), x, 0, arr.GetLength(0));

Edit2: It also looks like casting arrays with lowerbounds != 0 works for fine, if there are more than 1 dimension, you can read more here, where Jon Skeet seems to answer why that happens.

Edit3: To make response less ambiguous, following djna's comments. This is how you could obtain string[] out of object returned by a method, that can't be cast to string[] directly, because it has lowerBound != 0:

Array arr = (Array)xlApp.Run("Foo", ... missing args ...); //Here I assume that .Run() method is returning object, or something that has to be casted to Array.
string[] result = new string[arr.GetLength(0)];
Array.Copy(arr, arr.GetLowerBound(0), result, 0, arr.GetLength(0)); // Here data is copied, but only references in this scenario


标签: c# vba com interop