通用 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>,并且编译器可以推断 TSite

由于您没有使用 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]";
    }
}