Mar*_*the 64 .net c# for-loop c#-3.0
在C#3.0中,我喜欢这种风格:
// Write the numbers 1 thru 7
foreach (int index in Enumerable.Range( 1, 7 ))
{
Console.WriteLine(index);
}
Run Code Online (Sandbox Code Playgroud)
在传统的for循环:
// Write the numbers 1 thru 7
for (int index = 1; index <= 7; index++)
{
Console.WriteLine( index );
}
Run Code Online (Sandbox Code Playgroud)
假设'n'很小,所以性能不是问题,是否有人反对传统风格的新风格?
mqp*_*mqp 52
我发现后者的"最小到最大"格式比Range为此目的的"最小计数" 格式更清晰.另外,我认为从这样的规范做出这样的改变并不是一个好习惯,这种改变不是更快,更短,不熟悉,也不是更明确.
也就是说,我并不反对这个想法.如果你对我的语法看起来像foreach (int x from 1 to 8)那样,我可能会同意这将是一个for循环的改进.但是,Enumerable.Range非常笨重.
Luk*_*keH 39
这只是为了好玩.(我自己只使用标准的" for (int i = 1; i <= 10; i++)"循环格式.)
foreach (int i in 1.To(10))
{
Console.WriteLine(i); // 1,2,3,4,5,6,7,8,9,10
}
// ...
public static IEnumerable<int> To(this int from, int to)
{
if (from < to)
{
while (from <= to)
{
yield return from++;
}
}
else
{
while (from >= to)
{
yield return from--;
}
}
}
Run Code Online (Sandbox Code Playgroud)
您也可以添加Step扩展方法:
foreach (int i in 5.To(-9).Step(2))
{
Console.WriteLine(i); // 5,3,1,-1,-3,-5,-7,-9
}
// ...
public static IEnumerable<T> Step<T>(this IEnumerable<T> source, int step)
{
if (step == 0)
{
throw new ArgumentOutOfRangeException("step", "Param cannot be zero.");
}
return source.Where((x, i) => (i % step) == 0);
}
Run Code Online (Sandbox Code Playgroud)
Mik*_*per 15
在C#6.0中使用
using static System.Linq.Enumerable;
Run Code Online (Sandbox Code Playgroud)
你可以简化它
foreach (var index in Range(1, 7))
{
Console.WriteLine(index);
}
Run Code Online (Sandbox Code Playgroud)
对于已经解决的问题,这似乎是一个漫长的啰嗦方法.这背后有一个完整的状态机Enumerable.Range并不是真正需要的.
传统格式是发展的基础,也是所有人都熟悉的.我觉得你的新风格没什么好处.
实际上,你可以做到这一点在C#中(通过提供To与Do作为扩展方法int,并IEnumerable<T>分别对应).
1.To(7).Do(Console.WriteLine);
Run Code Online (Sandbox Code Playgroud)
SmallTalk永远!
正如 Nick Chapsas 在他出色的YouTube 视频中指出的那样,传统迭代和范围迭代之间没有显着的性能差异。即使基准测试也显示,少量迭代的情况下也存在纳秒级的差异。当循环变得相当大时,差异几乎消失了。
这是一种在范围循环中迭代其内容的优雅方法:
private static void Test()
{
foreach (var i in 1..5)
{
}
}
Run Code Online (Sandbox Code Playgroud)
使用此扩展:
public static class Extension
{
public static CustomIntEnumerator GetEnumerator(this Range range)
{
return new CustomIntEnumerator(range);
}
public static CustomIntEnumerator GetEnumerator(this int number)
{
return new CustomIntEnumerator(new Range(0, number));
}
}
public ref struct CustomIntEnumerator
{
private int _current;
private readonly int _end;
public CustomIntEnumerator(Range range)
{
if (range.End.IsFromEnd)
{
throw new NotSupportedException();
}
_current = range.Start.Value - 1;
_end = range.End.Value;
}
public int Current => _current;
public bool MoveNext()
{
_current++;
return _current <= _end;
}
}
Run Code Online (Sandbox Code Playgroud)
我喜欢这种实施方式。但是,这种方法的最大问题是它无法在异步方法中使用它。
我认为foreach + Enumerable.Range不太容易出错(你控制较少,错误的方法较少,比如减少体内的索引,所以循环永远不会结束等)
可读性问题是关于Range函数语义,它可以从一种语言变为另一种语言(例如,如果只给出一个参数,它将从0或1开始,或者是包含或排除结束,还是第二个参数是计数而不是结束值).
关于性能,我认为编译器应该足够聪明以优化两个循环,以便它们以相似的速度执行,即使是大范围(我认为Range不会创建集合,但当然是迭代器).
我想要一些其他语言的语法,如Python,Haskell等.
// Write the numbers 1 thru 7
foreach (int index in [1..7])
{
Console.WriteLine(index);
}
Run Code Online (Sandbox Code Playgroud)
幸运的是,我们现在得到F#:)
至于C#,我将不得不坚持使用这种Enumerable.Range方法.
我有点喜欢这个主意.它非常像Python.这是几行中的我的版本:
static class Extensions
{
public static IEnumerable<int> To(this int from, int to, int step = 1) {
if (step == 0)
throw new ArgumentOutOfRangeException("step", "step cannot be zero");
// stop if next `step` reaches or oversteps `to`, in either +/- direction
while (!(step > 0 ^ from < to) && from != to) {
yield return from;
from += step;
}
}
}
Run Code Online (Sandbox Code Playgroud)
它像Python一样工作:
0.To(4) → [ 0, 1, 2, 3 ]4.To(0) → [ 4, 3, 2, 1 ]4.To(4) → [ ]7.To(-3, -3) → [ 7, 4, 1, -2 ]由于这个问题,我尝试了一些方法来想出一个很好的语法,而无需等待一流的语言支持。这是我所拥有的:
using static Enumerizer;
// prints: 0 1 2 3 4 5 6 7 8 9
foreach (int i in 0 <= i < 10)
Console.Write(i + " ");
Run Code Online (Sandbox Code Playgroud)
<=不是和之间的区别<。
我还在GitHub 上创建了一个概念验证存储库, 具有更多功能(反向迭代、自定义步长)。
上述循环的最小且非常有限的实现如下所示:
public readonly struct Enumerizer
{
public static readonly Enumerizer i = default;
public Enumerizer(int start) =>
Start = start;
public readonly int Start;
public static Enumerizer operator <(int start, Enumerizer _) =>
new Enumerizer(start);
public static Enumerizer operator >(int _, Enumerizer __) =>
throw new NotImplementedException();
public static IEnumerable<int> operator <=(Enumerizer start, int end)
{
for (int i = start.Start; i < end; i++)
yield return i;
}
public static IEnumerable<int> operator >=(Enumerizer _, int __) =>
throw new NotImplementedException();
}
Run Code Online (Sandbox Code Playgroud)
@Luke:我重新实现了你的To()扩展方法并使用了这个Enumerable.Range()方法来实现它.这样它就会缩短一点,并尽可能使用.NET给我们提供的基础设施:
public static IEnumerable<int> To(this int from, int to)
{
return from < to
? Enumerable.Range(from, to - from + 1)
: Enumerable.Range(to, from - to + 1).Reverse();
}
Run Code Online (Sandbox Code Playgroud)
我认为Range对于处理某些范围的内联非常有用:
var squares = Enumerable.Range(1, 7).Select(i => i * i);
Run Code Online (Sandbox Code Playgroud)
你们每个人都可以.需要转换为列表,但保持紧凑,这是你想要的.
Enumerable.Range(1, 7).ToList().ForEach(i => Console.WriteLine(i));
Run Code Online (Sandbox Code Playgroud)
但除了像这样的东西,我会使用传统的for循环.
| 归档时间: |
|
| 查看次数: |
39197 次 |
| 最近记录: |