使用IList <t>和IReadOnlyList <{>

时间:2018-03-26 10:18:36

标签: c# overloading overload-resolution

我有一个方法,我想在我的解决方案中采取所有类似列表的对象。在.NET 4.5之前,这很简单:

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

但是,.NET 4.5引入了IReadOnlyList<T>,这种方法也适用于。{/ p>

我不能只改变签名以取IReadOnlyList<T>,因为有些地方我会将这种方法应用于IList<T>专门输入的内容。

该算法无法在IEnumerable<T>上运行,并且过于频繁地使用(并且对象太大)无法在每次调用时使用IEnumerable<T>并创建新的List<T>。 / p>

我尝试过添加一个重载:

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

...但是这不会编译实现两个接口(T[]List<T>和许多其他类型)的任何东西,因为编译器无法确定使用哪种方法(特别是因为他们拥有相同的身体而烦人,所以没关系)。

我不想添加带MethodT[]的{​​{1}}的重载,以及实现这两个接口的所有其他类型的重载。

我该如何做到这一点?

4 个答案:

答案 0 :(得分:4)

这可能是实际检查运行时类型有用的场合之一:

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

您仍需要重复代码,因为您需要IListIReadOnlyList的单独实现,因为您没有可以利用的通用接口,但至少可以避免不明确的呼叫问题。< / p>

答案 1 :(得分:2)

您最好的选择是进行全局搜索并将IList替换为IReadOnlyList。如果没有编译器错误那么你应该没问题。

如果您使用的是IList.Add,那么您应该只收到编译器错误 - 无论如何这都是蛮干的,因为数组不支持Add

答案 2 :(得分:0)

您可以更改Method调用的代码吗? 如果您创建这样的方法怎么办:

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

答案 3 :(得分:-1)

也许你最好的解决方案是研究为什么你的算法不能在IEnumerable上运行并改变它。您使用的IList<T>IReadOnlyList<T>特定成员是否可以替换IEnumerable<T>中提供的成员?例如:

// instead of
int c = list.Count;

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

编辑:忽略下面的废话。我要离开它,以便评论继续有意义。

您不应在任何课程中同时实施IList<T>IReadOnlyList<T>IList规范中唯一的附加成员用于写入列表。如果您的列表是只读的,则不需要这样做。我认为您需要更改任何实现两者的类,以便在使用它们时可以选择正确的方法。

但是,由于IReadOnlyList<T>中的所有成员都包含在IList<T>中(以及来自IReadOnlyCollection<T>的成员),我想知道.Net中的IList<T>是否应该实际更改这样它就会继承IReadOnlyList<T>接口,而不是复制成员。这并不能帮助你。