Home > Software engineering >  How do I join a collection if I don't know its type at compile-time?
How do I join a collection if I don't know its type at compile-time?

Time:04-23

We have a boxed list of strings:

object myList = new List<string> { "str1", "str2" };

We want to use String.Join and obtain "str1,str2". If we do

String.Join(",",myList)

It returns System.Collections.Generic.List`1[System.String] instead. How do we deal with this without changing the declaration of myList?

This is just a specific example. The type need not always be List<string>, we need to do myList.GetType() to obtain that info.

CodePudding user response:

If you don't know the type of the boxed collection, you could write a helper method to unbox and join it:

public string UnboxAndJoin(string separator, object obj)
{
    if (obj is IEnumerable enumerable)
    {
        return string.Join(separator, enumerable.Cast<object>());
    }
    else
    {
        throw new ArgumentException("Object is not an IEnumerable");
    }
}

Usage:

object myList = new List<string> { "str1", "str2" };
Console.WriteLine(UnboxAndJoin(",", myList));       // str1,str2

CodePudding user response:

You are getting System.Collections.Generic.List`1[System.String] and that's the expected result in your case.

The overload resolution for String.Join is chosing the following overload in your case:

public static string Join (string? separator, params object?[] values);

As documented here the Object.ToString() method is called on each object of the values parameter. Quotes from the documentation:

The string representation of each object in the array is derived by calling that object's ToString method.

The only object in the values parameter is an instance of the List<string> class. This class doesn't override the base implementation of ToString() defined in the Object class, so the fully qualified name of the class is returned when ToString() is called on any instance of the class itself.

That's why you are getting the string System.Collections.Generic.List`1[System.String] as the output of your code.

If your desired output is the string "str1,str2", then the overload of String.Join that you really want to call is the following:

public static string Join (string? separator, System.Collections.Generic.IEnumerable<string?> values);

In order to call this overload, you need to downcast the myList variable to the List<string> type:

String.Join(",", (List<string>) myList)

If don't know the actual type of the object that you have in the myList variable, you can be defensive and do the following:

if (myList is IEnumerable<string> values) 
{
  var message = String.Join(",", values);
  Console.WriteLine(message);
}
  • Related