简体   繁体   English

使用IList进行C#重载解析 <T> 和IReadOnlyList <T>

[英]C# overload resolution with IList<T> and IReadOnlyList<T>

I have a method which I'd like to take all list-like objects in my solution. 我有一个方法,我想在我的解决方案中采取所有类似列表的对象。 Before .NET 4.5, this was simple: 在.NET 4.5之前,这很简单:

public static T Method<T>(IList<T> list)
{
    // elided
}

However, .NET 4.5 introduced IReadOnlyList<T> , which this method should also apply to. 但是,.NET 4.5引入了IReadOnlyList<T> ,该方法也应该适用于此。

I can't just change the signature to take an IReadOnlyList<T> , as there are places where I apply the method to something specifically typed as an IList<T> . 我不能只改变签名来获取IReadOnlyList<T> ,因为有些地方我将这个方法应用于特定类型的IList<T>

The algorithm can't run on IEnumerable<T> , and it's used too frequently (and with too large objects) to take an IEnumerable<T> and create a new List<T> on every call. 该算法不能在IEnumerable<T>上运行,并且它太频繁地使用(并且对象太大)来获取IEnumerable<T>并在每次调用时创建一个新的List<T>

I've tried adding an overload: 我试过添加一个重载:

public static T Method<T>(IReadOnlyList<T> list)
{
    // elided
}

... but this won't compile for anything which implements both interfaces ( T[] , List<T> , and numerous other types), as the compiler can't determine which method to use (particularly annoying as they have the same body, so it doesn't matter). ...但是这不能编译实现两个接口( T[]List<T>和许多其他类型)的任何东西,因为编译器无法确定使用哪种方法(特别烦人,因为它们具有相同的身体,所以没关系)。

I don't want to have to add overloads of Method which take T[] , and List<T> , and every other type which implements both interfaces. 我不想添加带有T[]List<T>Method重载,以及实现这两个接口的所有其他类型。

How should I accomplish this? 我该怎么做到这一点?

This might be one of those occasions where actually checking the runtime type is useful: 这可能是实际检查运行时类型有用的场合之一:

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) { ... }

You still have to duplicate code in the sense that you need seperate implementations for IList and IReadOnlyList because there is no common interface you can leverage, but you at least avoid the ambigous call issue. 您仍然需要复制代码,因为您需要为IListIReadOnlyList单独实现,因为没有可以利用的通用接口,但您至少可以避免出现模糊的调用问题。

Your likely best bet is to do a global search and replace of IList to IReadOnlyList . 您可能最好的选择是进行全局搜索并将IList替换为IReadOnlyList If there are no compiler errors then you should be fine. 如果没有编译器错误,那么你应该没问题。

You should only receive compiler errors if you are using IList.Add - which is foolhardy anyway, since arrays don't support Add . 如果您使用的是IList.Add ,那么您应该只收到编译器错误 - 无论如何这都是IList.Add ,因为数组不支持Add

Can you change the code of Method calling? 你能改变方法调用的代码吗? What if you create a method like this: 如果您创建这样的方法怎么办:

    public static T1 Method<T1, T2>(T2 list) where T2 : IList<T1>, IReadOnlyList<T1>
    {
        return default(T1);
    }

In this case the calls look like this: 在这种情况下,调用如下所示:

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);

Another way to create two extension methods for IList and IReadOnlyList this way: 以这种方式为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);
    }

And call them like this: 并称他们为:

    string outVar1 = (listA as IReadOnlyList<string>).Test();
    string outVar2 = (listB as IList<string>).Test();

Maybe your best solution is to look into why your algorithm can't run on an IEnumerable and change that. 也许你最好的解决方案是调查为什么你的算法无法在IEnumerable上运行并改变它。 Are you using IList<T> or IReadOnlyList<T> -specific members that you could replace with members available in IEnumerable<T> ? 您是否正在使用IList<T>IReadOnlyList<T>特定成员,您可以使用IEnumerable<T>可用的成员替换它们? Eg: 例如:

// instead of
int c = list.Count;

// use
int c = list.Count();

EDIT: ignore the nonsense below. 编辑:忽略下面的废话。 I am leaving it so that the comments continue to make sense. 我要离开它,以便评论继续有意义。

You should not implement both IList<T> and IReadOnlyList<T> in any class. 您不应该在任何类中实现IList<T>IReadOnlyList<T> The only additional members in the IList specification are for writing to the list. IList规范中唯一的附加成员是写入列表。 You would not need to do that if your list is read only. 如果您的列表是只读的,则不需要这样做。 I think you need to change any classes that implement both so that the correct method can be selected when using them. 我认为您需要更改任何实现两者的类,以便在使用它们时可以选择正确的方法。

However, As all members of IReadOnlyList<T> are included in IList<T> (along with those derived from IReadOnlyCollection<T> ) I wonder if the IList<T> in .Net should actually be changed so that it inherits the IReadOnlyList<T> interface rather than duplicating the members. 但是,由于IReadOnlyList<T>所有成员都包含在IList<T> (以及从IReadOnlyCollection<T>派生的那些成员),我想知道.Net中的IList<T>是否应该实际更改,以便它继承IReadOnlyList<T>界面而不是复制成员。 Not that that helps you now. 这并不是说现在有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM