使用 IList<T> 和 IReadOnlyList<T> 的 C# 重载解析
C# overload resolution with IList<T> and IReadOnlyList<T>
我有一个方法,我想在我的解决方案中使用所有 list-like objects。在 .NET 4.5 之前,这很简单:
public static T Method<T>(IList<T> list)
{
// elided
}
然而,.NET 4.5 引入了IReadOnlyList<T>
,这种方法应该也适用。
我不能只更改签名以采用 IReadOnlyList<T>
,因为在某些地方我将该方法应用于专门键入为 IList<T>
的内容。
该算法无法在 IEnumerable<T>
上 运行,而且它的使用过于频繁(并且 objects 太大)无法获取 IEnumerable<T>
并创建一个新的List<T>
每次调用。
我试过添加重载:
public static T Method<T>(IReadOnlyList<T> list)
{
// elided
}
... 但是这不会编译任何实现两个接口(T[]
、List<T>
和许多其他类型)的东西,因为编译器无法确定使用哪种方法(特别烦人,因为他们有相同的body,所以没关系)。
我不想添加需要 T[]
和 List<T>
的 Method
的重载,以及实现这两个接口的所有其他类型。
我该如何完成?
您可能最好的选择是进行全局搜索并将 IList
替换为 IReadOnlyList
。如果没有编译错误那么你应该没问题。
只有在使用 IList.Add
时才会收到编译器错误 - 无论如何这是有勇无谋的,因为数组不支持 Add
.
也许您最好的解决方案是研究为什么您的算法不能在 IEnumerable 上 运行 并更改它。您是否正在使用 IList<T>
或 IReadOnlyList<T>
特定成员,您可以用 IEnumerable<T>
中可用的成员替换这些成员?例如:
// instead of
int c = list.Count;
// use
int c = list.Count();
编辑:忽略下面的废话。我离开它是为了让评论继续有意义。
您不应在任何 class 中同时实施 IList<T>
和 IReadOnlyList<T>
。 IList
规范中唯一的附加成员用于写入列表。如果您的列表是只读的,则不需要这样做。我认为您需要更改实现两者的任何 classes,以便在使用它们时可以选择正确的方法。
但是,由于 IReadOnlyList<T>
的所有成员都包含在 IList<T>
中(以及从 IReadOnlyCollection<T>
派生的成员),我想知道 .Net 中的 IList<T>
是否真的应该进行更改,以便它继承 IReadOnlyList<T>
接口而不是复制成员。不是那个现在对你有帮助。
能改一下方法调用的代码吗?
如果您创建这样的方法会怎样:
public static T1 Method<T1, T2>(T2 list) where T2 : IList<T1>, IReadOnlyList<T1>
{
return default(T1);
}
在这种情况下,调用如下所示:
List<string> listA = new List<String>();
ReadOnlyCollection<string> listB = listA.AsReadOnly();
string outVar1 = Method<string, List<string>>(listA);
string outVar2 = Method<string, ReadOnlyCollection<string>>(listB);
另一种为 IList 和 IReadOnlyList 创建两个扩展方法的方法:
public static T Test<T>(this IList<T> source)
{
return default(T);
}
public static T Test<T>(this IReadOnlyList<T> source)
{
return default(T);
}
并这样称呼他们:
string outVar1 = (listA as IReadOnlyList<string>).Test();
string outVar2 = (listB as IList<string>).Test();
这可能是实际检查运行时类型有用的情况之一:
public static T Method<T>(IEnumerable<T> source)
{
if (source is IList<T> list)
return Method(list);
if (source is IReadOnlyList<T> readOnly)
return Method(readOnly);
return Method(source.ToList() as IList<T>);
}
private static T Method<T>(IReadOnlyList<T> list) { ... }
private static T Method<T>(IList<T> list) { ... }
你仍然需要复制代码,因为你需要为 IList
和 IReadOnlyList
单独实现,因为没有你可以利用的通用接口,但你至少避免了模棱两可的调用问题.
我有一个方法,我想在我的解决方案中使用所有 list-like objects。在 .NET 4.5 之前,这很简单:
public static T Method<T>(IList<T> list)
{
// elided
}
然而,.NET 4.5 引入了IReadOnlyList<T>
,这种方法应该也适用。
我不能只更改签名以采用 IReadOnlyList<T>
,因为在某些地方我将该方法应用于专门键入为 IList<T>
的内容。
该算法无法在 IEnumerable<T>
上 运行,而且它的使用过于频繁(并且 objects 太大)无法获取 IEnumerable<T>
并创建一个新的List<T>
每次调用。
我试过添加重载:
public static T Method<T>(IReadOnlyList<T> list)
{
// elided
}
... 但是这不会编译任何实现两个接口(T[]
、List<T>
和许多其他类型)的东西,因为编译器无法确定使用哪种方法(特别烦人,因为他们有相同的body,所以没关系)。
我不想添加需要 T[]
和 List<T>
的 Method
的重载,以及实现这两个接口的所有其他类型。
我该如何完成?
您可能最好的选择是进行全局搜索并将 IList
替换为 IReadOnlyList
。如果没有编译错误那么你应该没问题。
只有在使用 IList.Add
时才会收到编译器错误 - 无论如何这是有勇无谋的,因为数组不支持 Add
.
也许您最好的解决方案是研究为什么您的算法不能在 IEnumerable 上 运行 并更改它。您是否正在使用 IList<T>
或 IReadOnlyList<T>
特定成员,您可以用 IEnumerable<T>
中可用的成员替换这些成员?例如:
// instead of
int c = list.Count;
// use
int c = list.Count();
编辑:忽略下面的废话。我离开它是为了让评论继续有意义。
您不应在任何 class 中同时实施 IList<T>
和 IReadOnlyList<T>
。 IList
规范中唯一的附加成员用于写入列表。如果您的列表是只读的,则不需要这样做。我认为您需要更改实现两者的任何 classes,以便在使用它们时可以选择正确的方法。
但是,由于 IReadOnlyList<T>
的所有成员都包含在 IList<T>
中(以及从 IReadOnlyCollection<T>
派生的成员),我想知道 .Net 中的 IList<T>
是否真的应该进行更改,以便它继承 IReadOnlyList<T>
接口而不是复制成员。不是那个现在对你有帮助。
能改一下方法调用的代码吗? 如果您创建这样的方法会怎样:
public static T1 Method<T1, T2>(T2 list) where T2 : IList<T1>, IReadOnlyList<T1>
{
return default(T1);
}
在这种情况下,调用如下所示:
List<string> listA = new List<String>();
ReadOnlyCollection<string> listB = listA.AsReadOnly();
string outVar1 = Method<string, List<string>>(listA);
string outVar2 = Method<string, ReadOnlyCollection<string>>(listB);
另一种为 IList 和 IReadOnlyList 创建两个扩展方法的方法:
public static T Test<T>(this IList<T> source)
{
return default(T);
}
public static T Test<T>(this IReadOnlyList<T> source)
{
return default(T);
}
并这样称呼他们:
string outVar1 = (listA as IReadOnlyList<string>).Test();
string outVar2 = (listB as IList<string>).Test();
这可能是实际检查运行时类型有用的情况之一:
public static T Method<T>(IEnumerable<T> source)
{
if (source is IList<T> list)
return Method(list);
if (source is IReadOnlyList<T> readOnly)
return Method(readOnly);
return Method(source.ToList() as IList<T>);
}
private static T Method<T>(IReadOnlyList<T> list) { ... }
private static T Method<T>(IList<T> list) { ... }
你仍然需要复制代码,因为你需要为 IList
和 IReadOnlyList
单独实现,因为没有你可以利用的通用接口,但你至少避免了模棱两可的调用问题.