如何正确阅读这行代码 - 接口作为对象



给定一行如下:

IEnumerable s = new List<int>() {1, 2}; 

我会把这一行读成: 创建一个 List 的新实例,其中每个成员必须具有 int32 数据类型,并将此实例命名为 "s",其类型为 IEnumerable。

我不确定这句话的最后一部分是否正确。我的意思是">IEnumerable 类型">部分,因为接口曾经是合约(在 c#8.0 + 中可能实现),我不确定我们是否可以正确地将它们称为对象。事实上,在这种情况下,"s"的类型是System.Collections.Generic.List而不是IEnumerable。

谢谢。

我只是要添加另一句话来解释为什么?

IEnumerable s = new List<int>() {1, 2}; 

我会把这一行读成:

创建一个 List 的新实例,其中每个成员必须具有 int32 数据类型,并将此实例命名为 "s",其类型为 IEnumerable。

我们指定 IEnumerable 而不是 List 作为变量s类型的原因是,当我们在程序中公开或传递s时,我们不希望调用者能够从中添加/删除。列表支持添加/删除/等,使用 IEnumerable 我们只允许枚举其值,这对于 API 场景很有用。

声明变量的类型告诉编译器如何处理变量。知道变量引用的对象List但编译器没有。您可以轻松地将s引用的对象更改为某种其他类型的集合,将s传递给更改其引用的变量的函数,因此编译器只知道方法和属性调用将基于IEnumerable接口绑定。如果您尝试在变量上调用不属于IEnumerableList方法(如AddIEnumerable)Select,编译器将不允许它。

所以我认为你的句子是准确的,如果你记得变量和变量引用的对象可以是不同的(但兼容的)类型。

你读得很好。给定以下表达式:

IEnumerable s = new List<int>() {1, 2}; 

我们说sIEnumerable类型的变量,它指的是包含两个元素的List<int>实例。

在代码中,将s定义为List<int>。说sIEnumerable甚至IEnurerable<int>型是不正确的:

using System;
using System.Collections;
using System.Collections.Generic;
namespace types
{
internal class Program
{
static void Main(string[] args)
{
IEnumerable s = new List<int>();
Console.WriteLine(s.GetType());
if(s is IEnumerable<int> enumerableType)
Console.WriteLine(enumerableType.GetType());
if (s is List<int> listType)
Console.WriteLine(listType.GetType());
}
}
}

输出:

System.Collections.Generic.List`1[System.Int32]
System.Collections.Generic.List`1[System.Int32]
System.Collections.Generic.List`1[System.Int32]

也许OP不理解的是List<T>实现(除其他外)接口IEnumerable<T>---从源代码:

public class List<T> : ICollection<T>, IEnumerable<T>, IEnumerable, IList<T>, IReadOnlyCollection<T>, IReadOnlyList<T>, ICollection, IList

我确信我在实现细节方面解释得是错误的,并且 .NET honchos 会纠正我,但这在实践中意味着您可以创建一个实际上是List<T>typeIEnumerable<T>变量并将其视为任一类型。但是,由于您将其声明为IEnurable<T>因此如果没有一些额外的语法,则无法将其用作List<T>

例如:

IEnumerable s = new List<int>();
s.Add(1);

不会编译,因为IEnumerable没有Add的定义。但你可以这样做:

IEnumerable s = new List<int>();
if(s is List<int> list)
list.Add(1);

更实用的是简单地将其声明为List<T>,因为IEnumerable所做的只是枚举,并且由于List实现了接口,因此您无需任何额外的代码即可获得该功能。

最新更新