之前,想把一个对象当集合使用,需要给这个类型构建索引器,为了foreach,还需要实现IEnumerable。.
public struct Season : IEnumerable
{
readonly string[] _arr;
public Season()
{
_arr = new string[4];
}
public string this[int index]
{
get => _arr[index];
set => _arr[index] = value;
}
public IEnumerator GetEnumerator()
{
for (var i = 0; i < _arr.Length; i++)
{
yield return _arr[i];
}
}
}
使用时,初始化,给每个元素赋值即可,然后就可以调用foreach来循环了。
var season = new Season();
season[0] = "春";
season[1] = "夏";
season[2] = "秋";
season[3] = "冬";
foreach (var s in season)
{
Console.WriteLine(s);
}
C#12引入了内联数组,让使用更简单,使用前,需要using ystem.Runtime.CompilerServices命名空间,然后内联数组定义如下:
[InlineArray(4)]
public struct Season
{
private string _name;
}
使用方式无变化,并且内联数组性能更好,原因具体参照官方说明。
var season = new Season();
season[0] = "春";
season[1] = "夏";
season[2] = "秋";
season[3] = "冬";
foreach (var s in season)
{
Console.WriteLine(s);
}
下面用BenchmarkDotNet来做个性能对比吧,完整代码如下:
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using System.Collections;
using System.Runtime.CompilerServices;
BenchmarkRunner.Run<Demo1>();
public class Demo1
{
Season0 season0;
Season1 season1;
[GlobalSetup]
public void Setup()
{
season0 = new Season0();
season0[0] = "春";
season0[1] = "夏";
season0[2] = "秋";
season0[3] = "冬";
season1 = new Season1();
season1[0] = "春";
season1[1] = "夏";
season1[2] = "秋";
season1[3] = "冬";
}
[Benchmark()]
public void P0()
{
foreach (var s in season0)
{
var s0 = s;
//Console.WriteLine(s);
}
}
[Benchmark]
public void P1()
{
foreach (var s in season1)
{
var s0 = s;
//Console.WriteLine(s);
}
}
}
[InlineArray(4)]
public struct Season0
{
private string _name;
}
public struct Season1 : IEnumerable
{
readonly string[] _arr;
public Season1()
{
_arr = new string[4];
}
public string this[int index]
{
get => _arr[index];
set => _arr[index] = value;
}
public IEnumerator GetEnumerator()
{
for (var i = 0; i < _arr.Length; i++)
{
yield return _arr[i];
}
}
}
下图是最后的对比结果,当然这是一个很粗糙的对比,但从性能上来看,内联数组不只要强数10万倍,虽然单次调用耗时可以忽略,但有时这个功能放在大循环中,累加起来的这些时间就不能忽视了。