Reputation: 1571
I have tried to write a method that converts any IList of things into a comma-separated list of those things as a string. It looks like this:
public static string ToStringList<T>(this T source) where T : IList<object>
{
string list_string = "[EMPTY]";
try
{
if (source != null && source.Count() > 0)
{
list_string = "";
foreach (var item in source)
{
//ToString unnecessarily written here to highlight the usage
list_string += $", {item.ToString()}";
}
}
}
catch
{
list_string = "[ERROR - could not list values]";
}
list_string = list_string.StartsWith(", ") ? list_string.Substring(2) : list_string;
return list_string;
}
I would like to use this method on an Observable collection of Sites:
public class Site
{
public string Name { get; set; }
public string code { get; set; }
public override string ToString()
{
return Name;
}
}
however, when I try to run the following code, I get a conversion error:
public ObservableCollection<Site> SelectedSites {get;set;}
//[some skipped code that inserts values into the ObservableCollection]
//Error: Cannot convert from Site to object
var sites = SelectedSites.ToStringList();
I understand why I get the conversion error - there is no way for the code to know how to convert the Site
into an object
. However, given that ToString()
exists on everything, is there a way that I can alter the method ToStringList()
such that it can accept an IList of any type?
I have read some articles and pages about IList (like this and this), but honestly they have as much confused as enlightened - is that because what I ask is impossible or so long winded as to be impractical (in which case I can find another way)?
I am using .NET Framework 4.8.
Upvotes: 0
Views: 464
Reputation: 270820
Your extension method isn't available on an ObservableCollection<Site>
, because an IList<Site>
isn't related to IList<object>
at all (See here for why).
You can instead use IList<T>
as the parameter type:
public static string ToStringList<T>(this IList<T> source)
Now this will be available on ObservableCollection<Site>
, because it implements IList<Site>
, and the compiler can infer that T
is Site
.
Since you are not using any of the specific things that IList<T>
provides, you can also define this method for the more general IEnumerable<T>
. However, calling Count()
on a general IEnumerable
could be an O(n) operation. You might want to use Any()
to check if there is any elements instead.
public static string ToStringList<T>(this IEnumerable<T> source)
Also note that you seem to be reinventing string.Join
a little bit:
public static string ToStringList<T>(this IEnumerable<T> source)
{
try
{
const string empty = "[EMPTY]";
if (source != null)
{
return string.Join(", ", source.Select(x => x.ToString()).DefaultIfEmpty(empty));
}
else
{
return empty;
}
}
catch
{
return "[ERROR - could not list values]";
}
}
Upvotes: 2
Reputation: 2378
Change
public static string ToStringList<T>(this T source) where T : IList<object>
To
public static string ToStringList<T>(this IList<T> source) where T : class
Upvotes: 2