问题描述
我尝试编写一种方法,将任何 IList 的事物转换为以逗号分隔的事物列表作为字符串。它看起来像这样:
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;
}
public class Site
{
public string Name { get; set; }
public string code { get; set; }
public override string ToString()
{
return Name;
}
}
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();
我明白为什么会出现转换错误 - 代码无法知道如何将 Site
转换为 object
。但是,鉴于 ToString()
存在于所有事物中,有没有办法更改方法 ToStringList()
使其可以接受任何类型的 IList?
我读过一些关于 IList 的文章和页面(比如 this 和 this),但老实说,他们既困惑又开明——是因为我问的是不可能的还是冗长的不切实际(在这种情况下我可以找到另一种方法)?
我使用的是 .NET Framework 4.8。
解决方法
改变
public static string ToStringList<T>(this T source) where T : IList<object>
到
public static string ToStringList<T>(this IList<T> source) where T : class
,
您的扩展方法在 ObservableCollection<Site>
上不可用,因为 IList<Site>
根本与 IList<object>
无关(请参阅 here 了解原因)。>
您可以改为使用 IList<T>
作为参数类型:
public static string ToStringList<T>(this IList<T> source)
现在这将在 ObservableCollection<Site>
上可用,因为它实现了 IList<Site>
,并且编译器可以推断出 T
是 Site
。
由于您没有使用 IList<T>
提供的任何特定内容,您也可以为更通用的 IEnumerable<T>
定义此方法。但是,在一般 Count()
上调用 IEnumerable
可能是 O(n) 操作。您可能想使用 Any()
来检查是否有任何元素。
public static string ToStringList<T>(this IEnumerable<T> source)
另请注意,您似乎在重新发明 string.Join
:
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]";
}
}