Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/310.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么List.AsReadOnly返回ReadOnlyCollection而Dictionary.AsReadOnly返回IReadOnlyDictionary?_C#_.net_Readonly Collection - Fatal编程技术网

C# 为什么List.AsReadOnly返回ReadOnlyCollection而Dictionary.AsReadOnly返回IReadOnlyDictionary?

C# 为什么List.AsReadOnly返回ReadOnlyCollection而Dictionary.AsReadOnly返回IReadOnlyDictionary?,c#,.net,readonly-collection,C#,.net,Readonly Collection,我遇到了这样一个例子,List.AsReadOnly()返回一个ReadOnlyCollection而不是IReadOnlyCollection这一事实让我很为难。由于返回的集合是字典的值,因此无法自动向上转换为IReadOnlyCollection。这似乎很奇怪,在查看.Net源代码后,我确认AsReadOnly()方法对List的作用与对Dictionary的不同,即返回具体类而不是接口 有人能解释为什么会这样吗?这种不一致性似乎是一种伤害,特别是因为我们希望在可能的情况下使用接口,尤其是在

我遇到了这样一个例子,
List.AsReadOnly()
返回一个
ReadOnlyCollection
而不是
IReadOnlyCollection
这一事实让我很为难。由于返回的集合是
字典
,因此无法自动向上转换为
IReadOnlyCollection
。这似乎很奇怪,在查看.Net源代码后,我确认
AsReadOnly()
方法对
List
的作用与对
Dictionary
的不同,即返回具体类而不是接口

有人能解释为什么会这样吗?这种不一致性似乎是一种伤害,特别是因为我们希望在可能的情况下使用接口,尤其是在公开的情况下

在我的代码中,我一开始认为,由于我的使用者只是一个私有方法,我可以将其参数签名从
IReadOnlyDictionary
更改为
IReadOnlyDictionary
。但是,后来我意识到这使得私有方法看起来可能会修改集合值,因此我在前面的代码中加入了一个恼人的显式强制转换,以便正确使用接口:

.ToDictionary(
   item => item,
   item => (IReadOnlyCollection<T>) relatedItemsSelector(item)
      .ToList()
      .AsReadOnly() // Didn't expect to need the direct cast
)
.ToDictionary(
项目=>项目,
item=>(IReadOnlyCollection)相关Items选择器(item)
托利斯先生()
.AsReadOnly()//不希望需要直接强制转换
)

哦,既然我总是把协变和逆变弄糊涂了,有人能告诉我是哪一个阻止了自动转换,并试着用一种明智的方式提醒我如何在将来记住它们吗?(例如,集合不是用于输入/输出参数的变量[co/contra])我理解为什么不能这样做,因为接口可以有许多实现,并且将字典的所有单个元素强制转换为请求的类型是不安全的。除非我连这个简单的方面都搞砸了,我不明白,在这种情况下,我希望你能帮我纠正一下…

原因是历史性的。
IReadOnly
*接口是在.NET 4.5中添加的,而
List.AsReadOnly()
是在.NET 2.0中重新添加的。改变它的返回类型将是一个突破性的改变

显式演员阵容并不坏。它甚至不是运行时强制转换,因为编译器可以静态地验证它(没有向IL发出强制转换)。顺便说一下,您可以将其强制转换为
IReadOnlyList
,它还提供对列表的索引访问。您还可以编写一个扩展方法来返回所需的类型(例如,
AsReadOnlyList()

关于{co,contra}方差,我发现使用C#关键字
in
(逆变)和
out
(协变)更容易记住
in
类型参数只能显示为input方法参数,而
out
类型参数只能显示为output(返回值)。接受参数(例如
Base
类型)的方法可以安全地与派生的
类型一起调用,因此在该方向上对
参数进行强制转换是安全的<代码>输出
正好相反

例如:

interface IIn<in T> { Set(T value); }
IIn<Base> b = ...
IIn<Derived> d = b;
d.Set(derived); // safe since any method accepting Base can handle Derived

interface IOut<out T> { T Get(); }
IOut<Derived> d = ...
IOut<Base> b = d;
b.Get(); // safe since any Derived is Base

你可以看到他们是如何避免通用变异带来的混乱。大概他们可以添加只写的接口,允许
(协变量)方向的
,但我猜他们没有发现这方面的很多价值。

原因是历史的。
IReadOnly
*接口是在.NET 4.5中添加的,而
List.AsReadOnly()
是在.NET 2.0中重新添加的。改变它的返回类型将是一个突破性的改变

显式演员阵容并不坏。它甚至不是运行时强制转换,因为编译器可以静态地验证它(没有向IL发出强制转换)。顺便说一下,您可以将其强制转换为
IReadOnlyList
,它还提供对列表的索引访问。您还可以编写一个扩展方法来返回所需的类型(例如,
AsReadOnlyList()

关于{co,contra}方差,我发现使用C#关键字
in
(逆变)和
out
(协变)更容易记住
in
类型参数只能显示为input方法参数,而
out
类型参数只能显示为output(返回值)。接受参数(例如
Base
类型)的方法可以安全地与派生的
类型一起调用,因此在该方向上对
参数进行强制转换是安全的<代码>输出
正好相反

例如:

interface IIn<in T> { Set(T value); }
IIn<Base> b = ...
IIn<Derived> d = b;
d.Set(derived); // safe since any method accepting Base can handle Derived

interface IOut<out T> { T Get(); }
IOut<Derived> d = ...
IOut<Base> b = d;
b.Get(); // safe since any Derived is Base

你可以看到他们是如何避免通用变异带来的混乱。大概他们可以添加只写的接口,允许
(协变量)方向的
,但我猜他们没有发现这方面的很多价值。

Oh!我假设它不会自动强制转换,因为它不是协变的,但现在我看到正是因为
IReadOnlyCollection
是只读的,编译器可以看到从派生类型强制转换到基类型是安全的。如果是这样的话,为什么我必须进行显式转换呢?协变和逆变只会在两个泛型接口之间进行转换并更改类型参数(从base到derived,反之亦然)时发生。您使用的强制转换只是强制转换-这是允许的,因为
ReadOnlyCollection
实现了
IReadOnlyList
。哦,糟糕,这很有意义。越来越清楚了。为什么不能隐式强制转换?强制转换是隐式的,例如,您可以编写
IReadOnlyList x=list.AsReadOnly()
,但在您的例子中,编译器只是推断lambda的类型,并将其用于
ToDictionary
方法。同样,与协方差无关-您不会更改任何类型参数。哦!我以为不会