0

鉴于以下情况:如果 IReadOnly(of T) 是从现存的 MutableEquivalent(of T) 构想出来的,那么简单地转换为可变版本允许完全访问,并且更改其他人可能依赖的对象静态元素/计数?下面的输出显示了我的“第三次注入”字符串,尽管迭代了一个只读集合。仅仅是礼貌和自我控制禁止了只读集合吗?您是否应该看到提供的接口,并承担其限制,强制转换,仅由于类型?感谢您对这个接口和其他喜欢它的真正承诺/保证的任何澄清。

编辑-这不是 IReadOnlyCollection<T>与 List.AsReadOnly() 的重复,因为我在我的问题中没有提到 List.AsReadOnly(),也没有提到 IReadOnlyCollection。这些是由响应者介绍的。这是一个关于 IReadOnly 接口后面的潜在可变列表暴露的问题。一些评论中有一些重叠,但是诸如“IReadOnly 对其底层可变列表(T)实际上做了什么?”之类的问题。重复了我的问题的精神。不是“这两个与只读有关的实体有什么区别?”,因为我只提到了一个。

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"};

}
4

2 回答 2

4

根据您的评论

我没有意识到接口对程序员来说更像是一种松散的保护,而不是一个“常量”式的突变障碍。…我错误地认为,从只读到可变的向下转换将是无效转换。

接口根本不打算作为任何形式的“保护”。它只是实现特定功能的承诺。

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

灵活性进来了,因为类型参数可以是协变的。IReadOnlyList<T1>这允许从IReadOnlyList<T2>where T1inherits的隐式转换T2

由接口的实现者决定是否提供真正的不变性。如果您希望一个集合真正不可变,您将使用ReadOnlyCollection<T>作为 的实现IReadOnlyList<T>,而不是List<T>. 您可以将任何IList<T>实现传递给ReadOnlyCollection<T>构造函数,并且新对象将IList<T>在不允许修改的情况下公开该对象的数据(直接......当然,您总是可以用反射作弊,即使是真正不可变的对象,而不仅仅是像这样的包装器ReadOnlyCollection<T>) .

对于任何接口,您始终只处理具有特定类型的特定对象,该类型始终实现某些功能,并且始终可以转换为原始类型以及它可能实现的任何其他接口。

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

于 2017-08-10T06:21:14.103 回答
1

的基础集合READONLY是一个可变列表,这就是创建hack变量时强制转换成功的原因。READONLY对其任何消费者都是只读的,但基础列表仍然可以改变。

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

于 2017-08-10T06:01:55.117 回答