C#:能否通过只读包装器调用List的LastIndexOf等成员方法?
解决方法
下面提供几种实用的方案,你可以根据实际场景选择:
方案1:给IReadOnlyList<T>编写LastIndexOf扩展方法
这是最通用的方案,不管传入的是List的只读包装还是其他实现IReadOnlyList<T>的类型,都能正常工作:
public static class ReadOnlyListExtensions { public static int LastIndexOf<T>(this IReadOnlyList<T> list, T value) { // 从列表末尾向前遍历,找到第一个匹配的元素索引 for (int i = list.Count - 1; i >= 0; i--) { if (EqualityComparer<T>.Default.Equals(list[i], value)) { return i; } } return -1; } } // 修改后的Bar函数 int Bar(IReadOnlyList<int> list, int value) { int i1 = list.IndexOf(value); int i2 = list.LastIndexOf(value); // 现在可以调用扩展方法 return i2 - i1; } // 调用示例 List<int> list = new List<int> { 1, 2, 3, 2, 1 }; Console.WriteLine(Bar(list.AsReadOnly(), 1)); // 输出4
方案2:针对ReadOnlyCollection<T>做适配
因为list.AsReadOnly()返回的是ReadOnlyCollection<T>,它内部持有原List的引用,可以通过Items属性直接调用原List的LastIndexOf方法:
int Bar(IReadOnlyList<int> list, int value) { int i1 = list.IndexOf(value); int i2; // 优先处理ReadOnlyCollection的情况 if (list is ReadOnlyCollection<int> readOnlyCol) { i2 = readOnlyCol.Items.LastIndexOf(value); } // 兼容直接传入List的场景 else if (list is List<int> concreteList) { i2 = concreteList.LastIndexOf(value); } // 其他情况回退到自定义遍历 else { i2 = list.LastIndexOf(value); // 复用方案1的扩展方法 } return i2 - i1; }
这个方案在处理List的只读包装时性能和原方法完全一致,但耦合了具体类型,适合你主要使用List的场景。
方案3:用LINQ快速实现(适合小数据量场景)
如果列表数据量不大,用LINQ的Reverse配合IndexOf可以快速实现,缺点是会生成新列表,大数据量下性能一般:
int Bar(IReadOnlyList<int> list, int value) { int i1 = list.IndexOf(value); // 转换反向列表的索引为原列表的索引 int reversedIndex = list.Reverse().ToList().IndexOf(value); int i2 = reversedIndex == -1 ? -1 : list.Count - 1 - reversedIndex; return i2 - i1; }
内容的提问来源于stack exchange,提问作者hzfsls
相关产品推荐
相关产品推荐

