C#中的9个“黑魔法”

2020-04-01 12:00:03于丽

注意其本质是调用了FormattableStringFactory.Create来创建一个类型。

5. yield return,与IEnumerable<T>类型;

是“黑魔法”,但有补充说明。

yield return除了用于IEnumerable<T>以外,还可以用于IEnumerableIEnumerator<T>IEnumerator

因此,如果想用C#来模拟C++/Javagenerator<T>的行为,会比较简单:

var seq = GetNumbers();
seq.MoveNext();
Console.WriteLine(seq.Current); // 0
seq.MoveNext();
Console.WriteLine(seq.Current); // 1
seq.MoveNext();
Console.WriteLine(seq.Current); // 2
seq.MoveNext();
Console.WriteLine(seq.Current); // 3
seq.MoveNext();
Console.WriteLine(seq.Current); // 4

IEnumerator<int> GetNumbers()
{
 for (var i = 0; i < 5; ++i)
  yield return i;
}

yield return——“迭代器”发布于C# 2.0

6. foreach循环,与IEnumerable<T>类型

是“鸭子类型”,有“操作空间”。

foreach不一定非要配合使用IEnumerable<T>类型,只要对象存在GetEnumerator()方法即可:

void Main()
{
 foreach (var i in new F())
 {
  Console.Write(i + ", "); // 1, 2, 3, 4, 5, 
 }
}

class F
{
 public IEnumerator<int> GetEnumerator()
 {
  for (var i = 0; i < 5; ++i)
  {
   yield return i;
  }
 }
}

另外,如果对象实现了GetAsyncEnumerator(),甚至也可以一样使用await foreach异步循环:

async Task Main()
{
 await foreach (var i in new F())
 {
  Console.Write(i + ", "); // 1, 2, 3, 4, 5, 
 }
}

class F
{
 public async IAsyncEnumerator<int> GetAsyncEnumerator()
 {
  for (var i = 0; i < 5; ++i)
  {
   await Task.Delay(1);
   yield return i;
  }
 }
}

await foreachC# 8.0随着异步流一起发布的,具体可见我之前写的《代码演示C#各版本新功能》。

7. using关键字,与IDisposable接口

是,也不是。

引用类型和正常的值类型using关键字,必须基于IDisposable接口。

ref structIAsyncDisposable就是另一个故事了,由于ref struct不允许随便移动,而引用类型——托管堆,会允许内存移动,所以ref struct不允许和引用类型产生任何关系,这个关系就包含继承接口——因为接口也是引用类型

但释放资源的需求依然存在,怎么办,“鸭子类型”来了,可以手写一个Dispose()方法,不需要继承任何接口: