c# -定义泛型函数重载的优先级
本文关键字:重载 优先级 函数 泛型 定义 | 更新日期: 2023-09-27 18:18:23
我有一个非常简单的递归定义的函数,它打印出任何列表的内容,定义如下:
static string ShowList<T>(IEnumerable<T> iterable)
{
return "[" + string.Join(", ", iterable.Select(e => ShowList(e))) + "]";
}
static string ShowList(string str)
{
return $"'"${str}'"";
}
static string ShowList<T>(T elem)
{
return elem.ToString();
}
可以看到,最低级别的重写是一个catch all,适用于任何参数。最高的重载只适用于可枚举的参数。理想情况下,我希望它首先检查并运行最特定的重载,然后如果它们都失败,则使用一般情况。但是我发现它总是直接得到一般情况,然后直接打印出Systems.Generic.Containers.List1[]
。是否有可能为某些重载提供比其他重载更高的优先级,以便编译器会在其他重载之前自动尝试这些重载?
在我看来,因为e
(在iterable.Select的委托中)是T类型,因此编译器将使用T类型过载。我建议,既然它所做的就是返回ToString()方法,消除它并将委托中的调用更改为ShowList(e.ToString())
。如果ToString()被重载,你很可能会得到有意义的数据,否则你会得到对象类型data。
至于发送List<List<T>>
,你需要一个不同的过载,一个不会接受它。
通用解析似乎有点奇怪。我认为,如果一个对象实现了通用的IEnumerable<T>
,那么这个匹配将比仅仅匹配通用的<T>
更具体,但显然,如果你有一个List<T>
,编译器会优先匹配<T>
而不是IEnumerable<T>
。我发现其他人在这里遇到了类似的问题,他们的解决方案是超载List<T>
,但这似乎不是一个好的解决方案,因为那样你就会超载所有实现IEnumerable<T>
的东西。我发现了一个简单的工作,使用is
操作符
static string ShowList<T>(IEnumerable<T> iterable)
{
return "[" + string.Join(", ", iterable.Select(e => ShowList(e))) + "]";
}
static string ShowList<T>(T elem)
{
if (elem is IEnumerable<object> iterable)
{
//This will force the call to the overload for IEnumerable<T>
return ShowList(iterable);
}
else
{
//This call will implicitly call ToString, so it covers the generic
//object case that needs to call ToString and the case where it is
//already a string, so the string overload is not needed.
return $"'"{elem}'"";
}
}
下面是测试这些方法的代码,故意将List和数组混合在一起,以显示它将适用于实现IEnumerable<T>
的不同项目
var list = new List<string[]>(){new string[2]{"hello", "world"}, new string[2]{"foo", "bar"}};
Console.WriteLine(ShowList(list)); //outputs: [["hello", "world"], ["foo", "bar"]]