I have a method that takes an object as an argument. The method needs to identify the type of object. This is easily accomplished for simple types like String and Double[], etc. I simply access the myObject.GetType().Name property.

But for generics like List<String[]>, etc. the Name property is always "List`1". I have to access the FullName property. This is cumbersome. Is their a better way?

Dani AI

Generated

Short version: treat the input as an enumerable of rows and convert each inner item to a string array instead of trying to decode every concrete generic type name. That avoids the big type-switch and works for both arrays and generic lists (so it fits 's need to produce a List<string[]> for the grid). This follows 's direction to rely on collection interfaces rather than string comparisons of type names.

Example implementation (handles arrays, List<T>, List<T[]>, etc.; special-cases string so it is not iterated):

public static List<string[]> ToStringRows(object data)
{
    if (data is string)
        return new List<string[]> { new[] { (string)data } };

    if (!(data is System.Collections.IEnumerable outer))
        return new List<string[]> { new[] { data?.ToString() ?? "" } };

    var rows = new List<string[]>();
    foreach (var item in outer)
    {
        if (item is System.Collections.IEnumerable inner && !(item is string))
        {
            // requires using System.Linq
            rows.Add(inner.Cast<object>().Select(x => x?.ToString() ?? "").ToArray());
        }
        else
        {
            rows.Add(new[] { item?.ToString() ?? "" });
        }
    }
    return rows;
}

Notes and pitfalls:

  • This handles typed arrays and generic lists uniformly (no GetGenericArguments switches). It will turn double[], List<double[]>, int[], etc. into rows of strings.
  • char[] will be treated as a sequence of characters (one string per char). If you want char[] joined into a single string cell, special-case it.
  • The code uses LINQ Cast/Select for brevity; add using System.Linq;.
  • Prefer generic, strongly-typed overloads when you control callers (better performance and compile-time safety). Use this reflection/collection-based approach when callers supply arbitrary runtime types.

For reference on the minimal interfaces used see the .NET docs for IEnumerable and Enumerable.Cast<T>.

Recommended Answers

All 8 Replies

For generic types you can test the IsGenericType property.
Then you need to use GetGenericArguments() to get an array of the types passed as arguments.
Just curious, but what are you doing that needs such analysis of types?
It is unusual to need to do such low level type reflection in normal apps.

I built a circuit that amplifies thermal noise from a transistor pair and feeds the output to a 16 bit ADC. I have a usb dio interface that collects the data in two bytes. The application crunches the raw bytes into various arrays of processed output (short[], double[], integer[], and char[])). Overall, its a truly random number generator.

This windows form application that presents datagridviews displaying the results. I now have a single PopulateGrid() method that converts any array or list of arrays to data rows/columns in string format.

Thanks for your great idea. I'm gonna use it.

Have you though of writing your code using generics.
That way you would not need to do any type checking as it would be managed by the compiler.

Well, I do use generics. I have a method:

public static void getGrid(System.Windows.Forms.DataGridView dg, object values, object columnHeaders)
      {
         //DO Stuff here that will convert any set of values or headers to a List<string[]> then create a data table;


      }

In my application I have several data types, some of which are generic lists. So far, the method handles byte[], double[], string[], int[], List<double[]>, List<string[]>, List<[int]>, List<char[]>, List<byte[]>.

I use these datagridviews frequently to display data of various types. Clearly, I could write several getGrid methods using specific types but I want to avoid the multiple overload approach. Am I right in my assumption that the only way to do this is to pass the argument as object.

No. You can write your own generic methods that are strongly typed but support many types.
Here is a little example.
Not quite what you need but hopefully shows you what you can do.

class GenericExample
    {
        // generic method to change an array of value types to a list of strings
        public List<string> Convert<T>(T[] values) where T :struct, IConvertible
        {
            List<string> list = new List<string>();
            if (values != null)
            {
                for (int i = 0; i < values.Length; i++)
                {
                    list.Add(values[i].ToString());
                }
            }
            return list;
        }

        public void testConvert()
        {
            int[] ints = new int[] { 123, 456, 6789 };
            double[] doubles = new double[] { 12.34, 34.45, 777.345 };

            //test with integer array
            List<string> intlist = Convert<int>(ints);
            //test with double array
            List<string> doublelist = Convert<double>(doubles);
        }
    }

Neat Good approach. I'll do that.

Using nick's method I now have:

public static List<string[]> ConvertObjectArrayToStringArray<T>(T[] values) where T : struct, IConvertible
      {
         List<string[]> list = new List<string[]>();
         string[] stringArray = new string[values.Length];
         if (values != null)
         {
            for (int i = 0; i < values.Length; i++)
            {
               stringArray[i] = values[i].ToString();
            }
         }
         list.Add(stringArray);
         return list;
      }

I added a similar method to handle Generic lists that are Lists of typed arrays (eg List<double[]>).:

public static List<string[]> ToListStringArrayFromList<T>(List<T> list)
      {
         List<T> genericList = new List<T>(list);
         Array ar = genericList.ToArray();
         List<string[]> result = new List<string[]>();
         foreach (Array arInner in (Array)ar)
         {
               List<string> temp = new List<string>();
               foreach (object value in arInner)
               {
                  temp.Add(value.ToString());
               }
               string[] returnListElement = new string[temp.Count];
               for (int j = 0; j < temp.Count; j++)
               {
                  returnListElement[j] = temp[j];
               }
               result.Add(returnListElement);
         }

         return result;
      }

Now, to convert objects that may either be either typed arrays or generic lists of typed arrays I have a method that conditionally negotiates the transactions:

public static List<string[]> ToListString(object data)
      {
         string ty = data.GetType().Name;
         Type t = data.GetType().UnderlyingSystemType;
         List<string[]> result = new List<string[]>();

         if (t.IsGenericType)
         {
            Type[] typ = t.GetGenericArguments();
            string genericTypeName = typ[0].Name.ToString();
            switch (genericTypeName)
            {
               case "Double[]":
                  result = ToListStringArrayFromList((List<double[]>)data);
                  break;
               case "Int32[]":
                  result = ToListStringArrayFromList((List<int[]>)data);
                  break;
               //others...
               case "String[]":
                  {
                     result = (List<string[]>)data;
                     break;
                  }
            }
         }
         else
         {
            switch (data.GetType().Name)
            {
               case "String[]":
                     result.Add((string[])data);
                     break;
               case "Double[]":
                     result = ConvertObjectArrayToStringArray<double>((double[])data);
                     break;
               //others...
               case "Int[]":
                     result = ConvertObjectArrayToStringArray<int>((int[])data);
                     break;
            }
         }
         return result;
      }

Is there a more elegant way (better than testing types in my switch block) of properly typing the object before calling my List<string[]> creation methods?

Why not adjust the generic function to work with the IEnumerable, IList or ICollection type instead of object[] or List<object> types. Thay way it covers both lists and arrays.

public static List<string[]> ToListStringArrayFromList<T>(IList<T> list) where T: struct, IConvertible
{
   // code to create string list form IList object (using ForEach might be best)
}

Or event without genrics

public static List<string[]> ToListStringArrayFromList(IList list)
{
   // code to create string list form IList object (using ForEach might be best)
}
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.