提问人:elldora 提问时间:1/16/2021 最后编辑:elldora 更新时间:1/18/2021 访问量:166
嵌套泛型方法的输出是什么?像 IEnumerable<IEnumerable<int>> Calculate() [重复]
What is the output of the method with nested generic type? like IEnumerable<IEnumerable<int>> Calculate() [duplicate]
问:
在 exercism.io 的帕斯卡三角形练习中,方法签名如下:
using System;
using System.Collections.Generic;
public static class PascalsTriangle
{
public static IEnumerable<IEnumerable<int>> Calculate(int rows)
{
…
}
}
很明显,Calculate 方法是具有嵌套泛型类型的方法。 我知道IEnumerable<...> 是泛型接口,它指示方法的类型。IEnumerable 是一个泛型接口,它适用于整数值类型。但是我无法理解嵌套泛型类型IEnumerable<IEnumerable>的含义和目的!
以下是我的问题:
- 这究竟是什么意思?
- Calculate 方法的返回类型应该是什么?
- 尽管 Calculate 方法不是从 IEnumerable 接口继承的,但我是否应该实现 IEnumerable.GetEnumerator()?
答:
1. 这到底是什么意思?
为了掌握这一点,了解什么是或它代表什么可能会有所帮助。文档中的定义是:IEnumerable<T>
公开枚举器,该枚举器支持对指定类型的集合进行简单迭代
在您的例子中,定义基本上可以翻译为:IEnumerable<IEnumerable<int>>
[...]支持对 s 集合的简单迭代,每个集合都支持对整数集合的简单迭代
IEnumerable<int>
这会导致嵌套迭代行为,该行为可以由“集合集合”表示。帕斯卡三角形就是一个很好的例子,因为你正好有:
[ // Outer collection
[1], // Inner collection 1
[1,1], // Inner collection 2
[1,2,1], // Inner collection 3
... // Inner collection n
]
代码中的一个示例是:
IEnumerable<int> innerCollection1 = new List<int> { 1 };
IEnumerable<int> innerCollection2 = new List<int> { 1, 1 };
IEnumerable<int> innerCollection3 = new List<int> { 1, 2, 1 };
IEnumerable<IEnumerable<int>> outerCollection = new List<IEnumerable<int>>
{
innerCollection1,
innerCollection2,
innerCollection3
};
然后,要获得内部的实际值,您需要遍历 outerCollection 中的每个 innerCollection。例如:
foreach (IEnumerable<int> innerCollection in outerCollection)
{
foreach (int value in innerCollection)
{
Console.Write(value);
Console.Write(" ");
}
Console.WriteLine();
}
其输出为:
1
1 1
1 2 1
2. Calculate 方法的返回类型应该是什么?
在 C# 中,您可以使用任何实现 的东西来表示这一点,例如列表列表:IEnumerable<int>
new List<List<int>>
{
new List<int> { 1 },
new List<int> { 1, 1 },
new List<int> { 1, 2, 1 },
// new List<int> { ... },
}
或数组数组:
new int[][]
{
new int[] { 1 },
new int[] { 1, 1 },
new int[] { 1, 2, 1 },
// new int[] { ... },
}
或数组列表:
new List<int[]>
{
new int[] { 1 },
new int[] { 1, 1 },
new int[] { 1, 2, 1 },
// new int[] { ... },
}
或一组列表:
new List<int>[]
{
new List<int> { 1 },
new List<int> { 1, 1 },
new List<int> { 1, 2, 1 },
// new List<int> { ... },
}
等等等等。
3.虽然 Calculate 方法不是从 IEnumerable 接口继承的,但我应该实现 IEnumerable.GetEnumerator() 吗?
您只需要在实现接口的自定义类型中实现。在您的例子中,您可以只返回一个已经实现该接口的类型(几乎是 System.Collections.Generic 中的任何内容),如上所示。显然,您只需要根据传递给方法的数量动态构建该实例,一个朴素的示例如下所示:IEnumerable.GetEnumerator()
IEnumerable
rows
public static IEnumerable<IEnumerable<int>> Calculate(int rows)
{
List<List<int>> outerList = new List<List<int>>();
for (int i = 0; i < rows; i++)
{
List<int> innerList = new List<int>();
// logic to build innerList
outerList.Add(innerList);
}
return outerList;
}
当调用时,例如将 3 传递为 ,应导致:rows
List<List<int>> outerList = new List<List<int>>
{
new List<int> { 1 }, // innerList 1
new List<int> { 1, 1 }, // innerList 2
new List<int> { 1, 2, 1 } // innerList 3
}
很明显,Calculate 方法是一种泛型方法
Calculate 不是一种通用方法。泛型方法的名称后带有尖括号,其中包含一个或多个“变量”,这些变量是您将在方法中引用的未知类型,这意味着它们可能如下所示:
MethodName<TypeReference>()
MethodName<TypeReference>(TypeReference param1)
TypeReference MethodName<TypeReference>()
MethodName<TypeReference1, TypeReference2>(TypeReference2 param1, TypeReference1 param2)
在尖括号中执行的操作是为将在运行时使用的类型建立名称别名。使用实际类型时,使用该别名的任何位置的行为都与使用实际类型相同:
T MethodName<T>(T param1);
//if you call it with a string, i.e. var v = MethodName<string>("hello");
//it will behave as if you defined it like:
string MethodName(string param1)
//if you call it with an int, it will behave as if you defined it as:
int MethodName(int param1)
我知道IEnumerable<...> 是泛型接口,它指示方法的类型。
方法没有“类型”。它们可能返回具有类型的东西,并且它们可能具有特定类型的参数,但方法本身没有类型
但是我无法理解嵌套泛型类型IEnumerable的含义和目的!
只要意识到它是一种类型在另一种类型中,它可以重复很长时间:
IEnumerable<string>
这是一种类型。它不是一个字符串,它是包含字符串集合的东西,它可以被枚举。IEnumerable 是事物的整个类型。就像出现在尖括号内并且是一种类型一样,也是一种事物。因为它是一种东西,所以它可以出现在其他东西的尖括号内:string
string
IEnumerable<string>
IList<string> //string is a type. It can appear inside angle brackets
IList<IEnumerable<string>> //IEnumerable<string> is a type, it can appear inside angle brackets
VB的。NET 的语法可能更清晰:
IList(Of String)
IList(Of IEnumerable(Of String))
以下是我的问题:
这究竟是什么意思?
这是一个“z 的 y 的 x”。如果是这样,它将是“x 的 w of y of z”。其他答案非常详细地涵盖了这一点,所以我不会IEnumerable<IList<IEnumerable<string>>>
Calculate 方法的返回类型应该是什么?
可以枚举的东西,充满了可以枚举的子事物。而那些可枚举的子事物必须是 的集合。在“z 的 y 的 x”中,x 和 y 是集合,z 是 int。int
尽管 Calculate 方法不是从 IEnumerable 接口继承的,但我是否应该实现 IEnumerable.GetEnumerator()?
你不继承一个接口,你实现它。您的类不实现 IEnumerable,因为它似乎不需要。如果要提供 GetEnumerator 方法并能够说,则可以实现 IEnumerable。foreach var whatever in myPascalsTriangle
你的方法被声明为返回一些已经实现 IEnumerable 的其他类型,因此你只需通过提供实现它的类型来遵守它。您不必在包含该方法的此类上实现它(就像您不必每次使用字符串时都实现字符串一样)
--
对你来说,这个答案的主要收获应该是巩固术语 - 我认为你可能会对类、方法、接口、返回类型和实现有点困惑。类代表事物,它们实现接口,这意味着可以保证它们具有具有特定名称并返回特定类型的方法。这意味着它们可以以共同的方式处理。但是,类不需要实现一个接口,这样它就可以有一个方法,该方法返回已实现该接口的另一种类型的类
上一个:如何使用 C 中的扩展方法处理包含受保护成员的数据#
下一个:打字稿类型的可选链接
评论
IEnumerable<int>
IEnumerable<IEnumerable<int>>
foreach (IEnumerable<int> row in resultFromCalculate) { foreach (int i in row) { ... } }
IENumerable<IEnumerable<Sheet>>
Calculate()
不是通用方法。