C# IReadOnlyList<t> 保护立即被沮丧破坏,还是我遗漏了什么?

C# IReadOnlyList<t> protection instantlly subverted by downcast, or am I missing something?

鉴于以下情况: 如果 IReadOnly(of T) 是从现存的 MutableEquivalent(of T) 中构想出来的,那么简单地转换为可变版本就允许完全访问,并且对其他人可能依赖的对象的更改具有静态 elements/count?下面的输出显示了我的 "THIRD INJECTION" 字符串,尽管遍历了一个只读集合。禁止将只读集合向下转换只是举止和自我控制吗?您是否应该看到所提供的接口,并仅由于类型而承受其限制,强制转换不变?感谢您对这个界面和其他人真正喜欢它的地方做出任何澄清 promise/guarantee。

编辑-这不是 IReadOnlyCollection<T> 与 List.AsReadOnly() 的副本,因为我没有在我的问题中提到 List.AsReadOnly(),也没有提到 IReadOnlyCollection。这些是由响应者介绍的。这是一个关于在 IReadOnly 接口后面暴露底层可变列表的问题。一些评论中有一些重叠,但是 "What does IReadOnly actually do for its underlying mutable List(of T)?" 之类的问题重复了我的问题的精神。不是"What is the difference between these two entities pertaining to read only?",因为我只提到了一个。

static class Program
{

    public static void Main()
    {
        List<string> hack = (List<string>) READONLY;
        hack.Add("THIRD INJECTION");

        foreach (var s in READONLY)
        {
            Console.WriteLine(s);
        }
    }

    public static readonly IReadOnlyList<string> READONLY = new List<string>{"@0", "@1"};

}

READONLY 的底层集合是一个可变列表,这就是在创建 hack 变量时转换实际上成功的原因。 READONLY 对于它的任何消费者都是只读的,但是底层列表仍然可以改变。

已更新:正如 Rufo 爵士指出的那样,通过 list.AsReadOnly() 公开列表将防止硬转换。

来自 :

I didn't realize the interface was more a loose protection for a programmer rather than a 'const'-esque' barrier to mutation. … I assumed, incorrectly, that a downcast from a readonly to mutable would be an invalid cast.

接口根本不是 "protection" 任何类型的。这只是实现特定功能的承诺。

IReadOnlyList<T> 的好处之一是语义,现在,C# 中的泛型类型变体具有灵活性。语义优势允许您以一种表达仅读取它而不修改它的意图的方式公开列表。

灵活性来了,因为类型参数可以协变。这允许从 IReadOnlyList<T1>IReadOnlyList<T2> 的隐式转换,其中 T1 继承 T2.

由接口的实现者决定是否提供真正的不变性。如果你想让一个集合真正不可变,你可以使用 ReadOnlyCollection<T> 作为 IReadOnlyList<T> 的实现,而不是 List<T>。您可以将任何 IList<T> 实现传递给 ReadOnlyCollection<T> 构造函数,新对象将公开该 IList<T> 对象的数据而不允许修改(直接……当然,您总是可以通过反射作弊,即使对象是真正不可变的,而不仅仅是像 ReadOnlyCollection<T>).

这样的包装器

使用 any 接口,你总是只处理一个特定的对象,它有一个特定的类型,那个类型总是实现一些功能,并且总是可以转换成原始的类型,以及它可能实现的任何其他接口。

将接口视为一种重要的 保护形式 是错误的。他们不是。它们只是表达一个对象能够.