Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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:

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

However, .NET 4.5 introduced IReadOnlyList<T>, which this method should also apply to.

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>.

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.

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

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.

How should I accomplish this?

like image 357
Simon W Avatar asked Mar 26 '18 10:03

Simon W


2 Answers

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.

like image 155
InBetween Avatar answered Sep 19 '22 20:09

InBetween


Your likely best bet is to do a global search and replace of IList to 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.

like image 21
mjwills Avatar answered Sep 22 '22 20:09

mjwills