Home > Mobile >  Write IEnumerable extension methods to join a collection of strings
Write IEnumerable extension methods to join a collection of strings

Time:09-01

I'm pretty new to C#, and I'm trying to write an extension method to join a collection of objects/strings with custom quote marks. I have 2 ways of implement it, trying to figure out which way is the standard approach.

1st method, define one method for each type I need:

public static string JoinToString(this IEnumerable<string> stringEnumerable, string delimiter = ",", char quote = '\'');
{
    return string.Join(delimiter, stringEnumerable.Select(item => quote   item   quote));
}
public static string JoinToString(this IEnumerable<int> intEnumerable, string delimiter = ",", char quote = '\'')
{
    return string.Join(delimiter, intEnumerable.Select(item => quote   item.ToString()   quote));
}

etc...


2nd method: define only object parameter so it can work with any type (just like Console.WriteLine(object))

public static string JoinToString(this IEnumerable<object> enumerable, string delimiter = ",", char quote = '\'')
{
    return string.Join(delimiter, enumerable.Select(item => quote   item.ToString()   quote));
}

which one is the commonly acceptable / standard approach? Thanks!

CodePudding user response:

The common/ standard approach when working with Linq/ extension methods is to use generics unless you have a reason not to. So

public static string JoinToString<T>(this IEnumerable<T> source, string delimiter = ",", char quote = '\'')
{
    return string.Join(delimiter, source.Select(item => $"{quote}{item}{quote}"));
}

For future reference, you can also apply constraints on the generic type parameter if you want to restrict it so only a certain set of types can be passed to the generic method, which is handy when you want to access properties or methods on the object

CodePudding user response:

I would go for the strongly typed version (1st). The issue with creating an extension method on this IEnumerable<object> is that you will see this extension method on ALL lists as every class inherits of object.

In a small codebase this would not be an issue, however I have seen codebases where your IDE and IntelliSense has too many options for irrelevant extension methods.

Keep it simple and small and solve on the issue at hand.

CodePudding user response:

There are several issues with your code:

  1. Since you implement public method you should validate input parameters (enumerable, delimiter)
  2. You should check if item contains either delimiter or quote.
  3. If item contains delimiter or / and quote you, probably, have to escape them
  4. You have to check item for null
  5. We usually extend generic IEnumerable<T>, not IEnumerable<object>

Something like this:

public static string JoinToString<T>(this IEnumerable<T> source,
                                          string delimiter = ",",
                                          char quote = '\'',
                                          char escape = '\'') {

  string Escape(string value) {
    if (escape == '\0') // in case we don't want to escape at all
      return value;

    StringBuilder sb = new StringBuilder(value.Length * 2);

    foreach (var c in value) {
      if (c == quote || c == escape)
        sb.Append(escape);

      sb.Append(c);
    }

    return sb.ToString(); 
  }

  if (source is null)
    throw new ArgumentNullException(nameof(source));
  if (delimiter is null)
    throw new ArgumentNullException(nameof(delimiter));

  return string.Join(delimiter, source
    .Select(item => item?.ToString() ?? "")
    .Select(item => $"{quote}{Escape(item)}{quote}"));
}
  • Related