Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.NET 4.0 Excel Interop issues with dynamic collections

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.

like image 566
J Pullar Avatar asked Jan 26 '11 17:01

J Pullar


2 Answers

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

like image 66
GreyCloud Avatar answered Oct 18 '22 21:10

GreyCloud


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

like image 33
Hans Passant Avatar answered Oct 18 '22 21:10

Hans Passant