通用 IList 方法使用什么类型
What Type to use for Generic IList Method
我曾尝试编写一种方法,将任何 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;
}
我想在网站的 Observable 集合上使用此方法:
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 and 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>
定义此方法。但是,在一般 IEnumerable
上调用 Count()
可能是一个 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]";
}
}
我曾尝试编写一种方法,将任何 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;
}
我想在网站的 Observable 集合上使用此方法:
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 and 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>
定义此方法。但是,在一般 IEnumerable
上调用 Count()
可能是一个 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]";
}
}