C# Yield

Search for a command to run...

No comments yet. Be the first to comment.
春节回家,跟老爸一起刷了小破球2。 之后忽然想到了这个话题:你愿意相信机器,还是人 (一) 春节的时候,陪老爸去配了一副眼镜。 因为前不久我也正好花重金配了一副,在之前做了很多的功课,诸如眼镜的前倾角、面弯、镜间距、单眼瞳高、单眼瞳距之类的知识,了解了一些配镜过程中应该注意的事项。 老家是一个小县城,虽然眼镜店遍地都是,但专业的还真没几个。在配镜的过程中,能注意到这些细节的眼镜店几乎没有。蔡司专业的三维定位的仪器,更是全县城都没有。 当我提出需要仪器辅助测量这些参数的时候,一个配镜师傅跟我说,...

哎,我一个个人项目基本上都没有超过过两位数的QPS的人,面试你天天问我缓存的这些问题,你们礼貌吗? 缓存穿透 是啥 当请求试图访问一个在缓存和数据库都不存在的 key时,因为缓存没有,所以请求会直接转发到数据库上。然而数据库里面也没有这个 key 的记录,所以也就没有办法将这个数据写入缓存。当下一次同样的请求来了的时候,还是会转发到数据库上。 在这种情况下,缓存基本上也就没用了,就像被穿透了一样,请求每次都会走到数据库,流量大时数据库可能会扛不住。 咋整 对请求进行校验。一些明显不合理的参数直...

什么是托管代码 托管代码就是执行过程交由运行时管理的代码。运行时一般是指 CLR,公共语言运行时。 CLR 负责提取托管代码、将其编译成机器代码,然后执行它。除此之外,运行时还负责自动内存管理、安全边界、类型安全等等。 如果在 .Net 里面直接调用 C/C++ 程序,此类代码也称为“非托管代码”。在非托管代码的环境中,操作系统将程序加载进内存,然后调用内部的二进制代码,所以从内存管理到安全等诸多因素都需要程序员自己处理。 正常使用 .Net 编写的代码,会先编译成中间语言 (IL)。执行的...

Merge weight (Amazon 2022 OA)

#CSharp #PubSub 发布-订阅模式 有些时候,发布-订阅模式也会被称为观察者模式,但其实,如果细分的话,这两者之间还是有些细微的差别的。 观察者模式是在主题者(Subject)内部,维护一个观察者(Observer)列表。然后当主题者的状态发生变更的时候,主题者可以通知观察者发生了变化。观察者可以主动访问主题者,获得变更。也可以在通知观察者的时候,直接带上变更的消息。 在观察者模式中,主题者和观察者还是存在部分的耦合。因此,我们可以引入一个中介,来接触这种耦合。 类 A(发布者)发生...

#CSharp #yield
yield就是生成了一个值之后,控制回到了调用方继续执行,执行完成后,需要下一个值的时候,会重新回到yield return之后的语句处,继续执行。
结合下面的程序,理解了这点之后,跟yield相关的知识基本就都了解了。
代码:
public static void Main()
{
var testClass = new TestClass();
Console.WriteLine("[Main] BeginTest");
foreach (var value in testClass)
{
Console.WriteLine($"[Main] Got Value {value}");
Console.WriteLine("[Main] Do some logic here");
Console.WriteLine("[Main] Try to get next value");
}
}
public class TestClass : IEnumerable<int>
{
public IEnumerator<int> GetEnumerator()
{
Console.WriteLine("[Class] Begin Generate");
for (var index = 0; index < 3; index++)
{
Console.WriteLine($"[Class] Generate {index}");
yield return index;
Console.WriteLine($"[Class] Finished send {index}");
}
Console.WriteLine("[Class] Finished Generate");
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
程序执行日志:
[Main] BeginTest
[Class] Begin Generate
[Class] Generate 0
[Main] Got Value 0
[Main] Do some logic here
[Main] Try to get next value
[Class] Finished send 0
[Class] Generate 1
[Main] Got Value 1
[Main] Do some logic here
[Main] Try to get next value
[Class] Finished send 1
[Class] Generate 2
[Main] Got Value 2
[Main] Do some logic here
[Main] Try to get next value
[Class] Finished send 2
[Class] Finished Generate
代码:
public static void Main()
{
var testClass = new TestClass();
testClass.Value = 1;
testClass.SubClasses = new List<TestClass>
{
new()
{
Value = 2,
SubClasses = new List<TestClass>
{
new() { Value = 3 },
new() { Value = 4 }
}
},
new() { Value = 5 }
};
foreach (var item in testClass)
{
Console.WriteLine(item);
}
}
public class TestClass : IEnumerable<int>
{
public IList<TestClass> SubClasses { get; set; }
public int Value { get; set; }
public IEnumerator<int> GetEnumerator()
{
yield return Value;
if (SubClasses is not { Count: > 0 }) { yield break; }
foreach (var subClass in SubClasses)
{
foreach (var item in subClass)
{
yield return item;
}
}
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
程序执行日志:
1
2
3
4
5
递归迭代器存在一定的风险,如果是不平衡二叉树的话,可能会很深,获取值的时候的递归迭代的成本较高。
C# 编译器在遇到迭代器的时候,会根据枚举数模式(Iterator Pattern)将代码展开成CLI。
在生成的代码中,C# 编译器会首先创建一个嵌套的私有类来实现 IEnumerator<T> 接口,以及它的 Current 属性和 MoveNext() 方法。
Current 属性返回与迭代器的返回类型对应的一个类型。
C# 编译器检查包含在迭代器中的代码,并在 MoveNext() 方法和 Current 属性中创建必要的代码来模拟它的行为。
取消更多的迭代
yield 语句只能在方法、用户自定义操作符、或者索引器或属性的 get 防蚊器方法中出现。成员不可以获取任何 ref 或 out 参数yield 语句不能在匿名语句或者 lambda 方法中出现yield 语句不能在 try 语句的 catch 和 final 子句中出现。除此之外,yield 语句能在 try 块中出现的前提是,它没有 catch 块