.NET 4.0 Excel Interop issues with dynamic collect

2019-01-19 06:05发布

问题:

In Excel you can return a dynamic array System.Object[*], from a series object using XValues. In .NET 3.5 you can access the elements in this object by casting it to and array, i.e.:

var values = (Array)series.XValues;

In .NET 4.0, this no longer works, and the message

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

is given.

Any ideas? The following doesn't work:

  • Casting it as dynamic.
  • Casting it to a System.Object[*].
  • Just placing the object in a for each loop.
  • Trying to access the value directly using values[1], neither when cast as a dynamic.

The values inside the array do show up in the debugger however.

回答1:

There are two distinct kind of arrays in .NET, a one dimensional 'vector' and multidimensional arrays. You got the latter back, a multidimensional array with a rank of 1. This will happen if the unmanaged code has returned a SAFEARRAY whose lower-bound isn't 0.

You can read the content of the array with Array.GetValue(). Or convert it, like this:

    private static object[] ConvertArray(Array arr) {
        int lb = arr.GetLowerBound(0);
        var ret = new object[arr.GetUpperBound(0) - lb + 1];
        for (int ix = 0; ix < ret.Length; ++ix) {
            ret[ix] = arr.GetValue(ix + lb);
        }
        return ret;
    }

Test:

    var native = Array.CreateInstance(typeof(object), new int[] { 42 }, new int[] { 1 });
    var dotnet = ConvertArray(native);

NOTE: you may have a problem in .NET 4.0 and up when you some COM type libraries, Office in particular. The property or method may return a variant that contains an array. Ends up as dynamic in your C# program. The C# compiler does not generate the proper binder code in that case. Work around that by casting first to (object), then to (Array).



回答2:

The answer above is useful but does not address the issue of how to cast to Array.

Under .Net versions before 4.0 a simple cast would work.

in C# 4.0 one must use

System.Array a = (System.Array)((object)  returnedObject ); // note order of brackets

see http://blogs.msdn.com/b/mshneer/archive/2010/06/01/oh-that-mysteriously-broken-visiblesliceritemslist.aspx