Home > Software engineering >  How do I implement an unknown Array type in C# .Net Core?
How do I implement an unknown Array type in C# .Net Core?

Time:08-04

I have the following code below but haven't figured out how to implement the var results = section so that result[c] = valuesArray; works properly?

    var result = Array.CreateInstance(typeof(Array), dt.Columns.Count);

            foreach (int c in Enumerable.Range(0, dt.Columns.Count))
            {
                // Create a list to hold values of the required type for the column
                var valuesArray = Array.CreateInstance(typeof(float), dt.Rows.Count);

                // Get the data to be written to the parquet stream
                for (int r = 0; r < dt.Rows.Count; r  )
                {
                    DataRow row = dt.Rows[r];

                    valuesArray.SetValue(row[c], r);
                }

                result[c] = valuesArray;

The error is:

Error: CS0021 = Cannot apply indexing with [] to an expression of type 'Array'

How do I instiate the Array so it works?

CodePudding user response:

Just as you set a value to valuesArray with the SetValue() method, you can do the same for result:

result.SetValue(valuesArray, c);

If you need to retrieve the value during iteration, you can use result.GetValue(c):

foreach (int c in result)
{
    var retrievedResult = result.GetValue(c);
}

CodePudding user response:

The Nice approach that I've tried and works correctly is:

 var result = (dynamic)Array.CreateInstance(typeof(Array), columnLength);

The sample code is:

int columnLength = 8;
var result = (dynamic)Array.CreateInstance(typeof(Array), columnLength);

foreach (int c in Enumerable.Range(0, columnLength)) {
    // Create a list to hold values of the required type for the column
    var valuesArray = Array.CreateInstance(typeof(float),columnLength);

    // Get the data to be written to the parquet stream
    for (int r = 0; r < columnLength; r  ) {

        valuesArray.SetValue(r, r);
    }

    result[c] = valuesArray;
}

foreach (var arr in result)
    foreach (var value in arr)
        Console.Write($"{value}\t");
Console.ReadLine();

The Output is:

0       1       2       3       4       5       6       7       0       1       2       3       4       5       6
        7       0       1       2       3       4       5       6       7       0       1       2       3       4
        5       6       7       0       1       2       3       4       5       6       7       0       1       2
        3       4       5       6       7       0       1       2       3       4       5       6       7       0
        1       2       3       4       5       6       7

CodePudding user response:

It looks like result.SetValue(valuesArray, c) will work.

You can also get the value with

result.GetValue(c);

So if you need to iterate through result you can write a foreach similar to the one you already wrote.

foreach (int c in Enumerable.Range(0, dt.Columns.Count))
{
   var x = result.GetValue(c);
}

CodePudding user response:

You can utilize generics for this. The only reflection you need is to execute the inner function once per column.

  • The initial array of arrays can be done without Array.CreateInstance
var method = this.GetType().GetMethod("GetArray");

var result = new Array[dt.Columns.Count];

for (int c = 0; c < dt.Columns.Count; c  )
{
    var generic = method.MakeGenericMethod(dt.Columns[c].DataType);
    result[c] = (Array)generic.Invoke(null, new[]{dt.Rows, c});
}
public static Array GetArray<T>(DataRowCollection rows, int c)
{
    var valuesArray = new T[rows.Count];
    for (int r = 0; r < rows.Count; r  )
    {
        DataRow row = rows[r];
        valuesArray[r] = (T)row[c];
    }
    return valuesArray;
}

In high performance scenarios, you could even cache a delegate to the generic function

static MethodInfo method = this.GetType().GetMethod("GetArray");

static Dictionary<Type, Func<DataRowCollection, int, Array>> funcs = new();
var result = new Array[dt.Columns.Count];

for (int c = 0; c < dt.Columns.Count; c  )
{
    if(!funcs.TryGetValue(dt.Columns[c].DataType, out var func)
    {
        func = funcs[dt.Columns[c].DataType] =
          (Func<DataRowCollection, int, Array>) method.MakeGenericMethod(dt.Columns[c].DataType)
             .CreateDelegate(typeof(Func<DataRowCollection, int, Array>));
    }
    result[c] = func(dt.Rows, c);
}
  • Related