Reputation: 13
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!
Upvotes: 1
Views: 491
Reputation: 186738
There are several issues with your code:
public
method you should validate input parameters (enumerable
, delimiter
)item
contains either delimiter
or quote
.item
contains delimiter
or / and quote
you, probably, have to escape themitem
for null
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}"));
}
Upvotes: 0
Reputation: 563
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.
Upvotes: 0
Reputation: 7910
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
Upvotes: 5