0

I am having trouble with what should be a simple cast of a multidimensional object array (object[,]) to a new data type (string[,]) for logging purposes. The format is a dynamic two dimensional array that has many columns and rows, but doesn't fit nicely into one of the generic collection objects offered in the framework. I would just strong type it as a string[,] all the way through the process, but I need the flexibility of the object array, because in some instances I will need to use different data types.

private List<KeyValuePair<string, object>> _dataList = new List<KeyValuePair<string, object>>();
private object[,] _dataArray;

public List<KeyValuePair<string, object>> RetrieveHistoricalData()
{

...

//Calling Method (for explaination and context purposes)

_log.Log ("\r\nRetrieveHistoricalData", "_dataList.Count: " + _dataList.Count);
_dataList.ForEach(dli => _log.Log ("\r\nRetrieveHistoricalData", "_dataList: " 
    + dli.Key + ((object[,])dli.Value)
    .CastTwoDimensionalArray<string>()
    .TwoDimensionalArrayToString()));

...

}

... Added An Extension method based on Jon Skeet's suggestions ...

internal static T[,] CastTwoDimensionalArray<T>(this object[,] dataArray)
{
    int rows = dataArray.GetLength(0);
    int columns = dataArray.GetLength(1);
    T[,] returnDataArray = new T[rows, columns];
    for (int row = 0; row < rows; row++)
    {
        for (int column = 0; column < columns; column++)
        {
            returnDataArray[row, column] =
                      (T)Convert.ChangeType(dataArray[row, column], typeof(T));
        }
    }
    return returnDataArray;
}

... Here's my own addition (only included because it is in the line I am executing) ...

internal static string TwoDimensionalArrayToString<T>(this T[,] dataArray)
{
    int rows = dataArray.GetLength(0);
    int columns = dataArray.GetLength(1);
    string returnString = "";
    for (int row = 0; row < rows; row++)
    {
        for (int column = 0; column < columns; column++)
        {
            returnString = returnString + "[" + row + "," + column + "] =>" + dataArray[row,column]+ " ;  ";
        }
    }

    return returnString;
}

I have edited the code above from the first post, but I am still receiving a System.InvalidCastException when trying to convert a System.Double to a System.String in the Generic extension method. I am working on a simple way to add some exceptions through type reflection to remove the remaining issue.

Thanks.

6
  • It looks like you didn't mention the language. Commented Jan 2, 2013 at 16:58
  • What's the definition of _dataList? Commented Jan 2, 2013 at 17:01
  • Sorry, I just added the _dataList definition. Commented Jan 2, 2013 at 17:03
  • Thanks, but I still can't really tell what the type of the object is that you insert into _dataList :) That would allow us to inspect why your cast to string[,] is failing. Commented Jan 2, 2013 at 17:04
  • Ameen, I actually misstated the object in the original post. I have now corrected it to show it was actually an object[,] to begin with, not a string[,]. Commented Jan 2, 2013 at 17:11

1 Answer 1

2

EDIT: You can only cast from object[,] to string[,] if the array involved really is a string[,] originally. For example, this is fine:

object[,] o = new string[,]
{
    { "x", "y" },
    { "a", "b" }
};
string[,] x = (string[,]) o;

... but this isn't:

object[,] o = new object[,]
{
    { "x", "y" },
    { "a", "b" }
};
string[,] x = (string[,]) o; // Bang!

Even though each element of the array is a string, it still isn't a string array. In the latter case, you'll need to write your own code to create a new array object and perform the element-wise conversion. For example, here's a generic method you can use to cast each element:

using System;

class Test
{
    static void Main()
    {
        object[,] o = new object[,]
        {
            { "x", "y" },
            { "a", "b" }
        };
        string[,] x = Cast2D<string>(o);
        Console.WriteLine(x[1, 1]); // "b"
    }

    static T[,] Cast2D<T>(object[,] input)
    {
        int rows = input.GetLength(0);
        int columns = input.GetLength(1);
        T[,] ret = new T[rows, columns];
        for (int i = 0; i < rows; i++)
        {
            for (int j = 0; j < columns; j++)
            {
                ret[i, j] = (T) input[i, j];
            }
        }
        return ret;
    }        
}

In your case you'd probably want:

object[,] array = (object[,]) financialDataObject;
string[,] financialData = Cast2D<string>(array);
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for the suggestion. I actually had to go back and change my first statement where I claimed the original field was a string[,]. It was actually an object[,] for its origin. I went back and looked at other portions of my code and noticed that I am expecting to receive a myriad of different types of historical data that I will have to be convert for, so I'll probably have to write a bunch of conversion logic inside of a generic method like the one you posted above.
Jon: The "crazy" array covariance of .NET 1 seems to work fine with 2D arrays. I just ran this code successfully: string[,] arr1 = { { "Hello", "this", }, { "is", "working", }, }; object[,] arr2 = arr1; Console.WriteLine(arr2[1, 1]);
@JeppeStigNielsen: You're absolutely right. I swear I tried it before posting, and the compiler told me there was no such conversion available. No idea what I was doing now. Will edit.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.