首页 > 解决方案 > 如何使 for 循环成为通用的?

问题描述

一个 for 循环

for (T i = a; i < b; i++)
{
    // do something
}

看起来很正常,对吧?

再看一眼,您会注意到T不是原始数据类型 - 泛型类型。仍然不应该是一个问题,你会想。T可以是任何东西,   不限于   数字(字符串,甚至是复杂对象),只要它具有可比性和可枚举性(即您需要对其应用约束where T: IEnumerable, IComparable)。

因为它不仅限于数字,而且由于 Eric 给出的答案适用于任何类型的对象,我不认为这个问题“是否存在限制我的通用方法数字类型?”

但回到这个问题:我也是这么想的,然后我开始玩弄这个问题并尝试写一些类似的东西

IEnumerable<T> Numbers<T>(T a, T b)
where T: IEnumerable, IComparable
{
    for (T i = a; i < b; i++)
    {
        yield return i;
    }
}

实现一个可用于 double、int、... 的数字生成器,这将是一个通用的 for 循环。约束IEnumerableIComparable只是告诉编译器可以枚举和比较这种类型的元素(因为循环中的i < b表达式for和增量),如果 C# 有这个,INumeric也是一个非常有用的约束(当然,这将隐含地具有可比性和可枚举性)。

令我惊讶的是,此示例无法编译,它会生成以下错误:

CS0019:运算符“<”不能应用于“T”类型的操作数和“T”
CS0023:运算符“++”不能应用于“T”类型的操作数

原因似乎是对数字没有限制,但似乎没有任何实用的解决方案可用,正如这里的一些答案所解释的那样。

注意:类似的(非通用)版本可以编译:

IEnumerable<double> Numbers(double a, double b)
{
    for (var i = a; i < b; i++)
    {
        yield return i;
    }
}

IEnumerable<int> Numbers(int a, int b)
{
    for (var i = a; i < b; i++)
    {
        yield return i;
    }
}

如果你有两者,你可以像调用它一样

var intNumbers = Numbers((int)1, 10);
var doubleNumbers = Numbers((double)1, 10);

并且由于参数的签名,选择了正确的版本。


本质上,问题是:

1.是否可以编写一个通用函数作为可以调用的函数

var intNumbers = Numbers<int>(1, 10);
var doubleNumbers = Numbers<double>(1, 10);

如我的第一个示例所示?

(我不确定正确的约束,我认为这样where T: IEnumerable, IComparable做是因为您需要比较i < b并且需要迭代到下一个更大的数字)。

2. a) 我如何编写一个通用约束来增加和比较类型变量T

2. b) 如果没有这样的约束,有没有办法用通用参数模拟 for 循环?

3. 如何使 for 循环成为通用的?

标签: c#.netgenerics

解决方案


一个for循环有四个部分:

  • 初始化当前状态
  • 测试当前状态,如果测试失败则停止
  • 执行一个动作
  • 创建一个新的当前状态

我们将离开它breakcontinue因为它们使事情变得相当复杂。

您希望将操作限制为产生值。美好的。那么我们想要的是Aggregate产生一个值的新版本:

public static IEnumerable<R> MyFor<S, R>(
  S initial, 
  Func<S, bool> test, 
  Func<S, S> increment, 
  Func<S, R> select) 
{

    for (S current = initial; test(current); current = increment(current))
        yield return select(current);

}

我们完成了。您现在可以for通过简单地提供必要的 lambdas 来制作您喜欢的任何循环:

static IEnumerable<double> MakeDoubles() => 
  MyFor(0.0, x => x <= 10.0, x => x + 1.0, x => x);

推荐阅读