当前位置: 首页 > news >正文

做外贸的专业网站网站服务器和空间大小

做外贸的专业网站,网站服务器和空间大小,php网站开发需要什么,西安sem竞价托管前言 当我们编写 C# 代码时#xff0c;经常需要处理大量的数据集合。在传统的方式中#xff0c;我们往往需要先将整个数据集合加载到内存中#xff0c;然后再进行操作。但是如果数据集合非常大#xff0c;这种方式就会导致内存占用过高#xff0c;甚至可能导致程序崩溃。 …前言 当我们编写 C# 代码时经常需要处理大量的数据集合。在传统的方式中我们往往需要先将整个数据集合加载到内存中然后再进行操作。但是如果数据集合非常大这种方式就会导致内存占用过高甚至可能导致程序崩溃。 C# 中的yield return机制可以帮助我们解决这个问题。通过使用yield return我们可以将数据集合按需生成而不是一次性生成整个数据集合。这样可以大大减少内存占用并且提高程序的性能。 在本文中我们将深入讨论 C# 中yield return的机制和用法帮助您更好地理解这个强大的功能并在实际开发中灵活使用它。 使用方式 上面我们提到了yield return将数据集合按需生成而不是一次性生成整个数据集合。接下来通过一个简单的示例我们看一下它的工作方式是什么样的以便加深对它的理解 foreach (var num in GetInts()) {Console.WriteLine(外部遍历了:{0}, num); }IEnumerableint GetInts() {for (int i 0; i 5; i){Console.WriteLine(内部遍历了:{0}, i);yield return i;} }首先在GetInts方法中我们使用yield return关键字来定义一个迭代器。这个迭代器可以按需生成整数序列。在每次循环时使用yield return返回当前的整数。通过1foreach循环来遍历 GetInts方法返回的整数序列。在迭代时GetInts方法会被执行但是不会将整个序列加载到内存中。而是在需要时按需生成序列中的每个元素。在每次迭代时会输出当前迭代的整数对应的信息。所以输出的结果为 内部遍历了:0 外部遍历了:0 内部遍历了:1 外部遍历了:1 内部遍历了:2 外部遍历了:2 内部遍历了:3 外部遍历了:3 内部遍历了:4 外部遍历了:4可以看到整数序列是按需生成的并且在每次生成时都会输出相应的信息。这种方式可以大大减少内存占用并且提高程序的性能。当然从c# 8开始异步迭代的方式同样支持 await foreach (var num in GetIntsAsync()) {Console.WriteLine(外部遍历了:{0}, num); }async IAsyncEnumerableint GetIntsAsync() {for (int i 0; i 5; i){await Task.Yield();Console.WriteLine(内部遍历了:{0}, i);yield return i;} }和上面不同的是如果需要用异步的方式我们需要返回IAsyncEnumerable类型这种方式的执行结果和上面同步的方式执行的结果是一致的我们就不做展示了。上面我们的示例都是基于循环持续迭代的其实使用yield return的方式还可以按需的方式去输出这种方式适合灵活迭代的方式。如下示例所示 foreach (var num in GetInts()) {Console.WriteLine(外部遍历了:{0}, num); }IEnumerableint GetInts() {Console.WriteLine(内部遍历了:0);yield return 0;Console.WriteLine(内部遍历了:1);yield return 1;Console.WriteLine(内部遍历了:2);yield return 2; }foreach循环每次会调用GetInts()方法GetInts()方法的内部便使用yield return关键字返回一个结果。每次遍历都会去执行下一个yield return。所以上面代码输出的结果是 内部遍历了:0 外部遍历了:0 内部遍历了:1 外部遍历了:1 内部遍历了:2 外部遍历了:2探究本质 上面我们展示了yield return如何使用的示例它是一种延迟加载的机制它可以让我们逐个地处理数据而不是一次性地将所有数据读取到内存中。接下来我们就来探究一下神奇操作的背后到底是如何实现的方便让大家更清晰的了解迭代体系相关。 foreach本质 首先我们来看一下foreach为什么可以遍历也就是如果可以被foreach遍历的对象被遍历的操作需要满足哪些条件这个时候我们可以反编译工具来看一下编译后的代码是什么样子的相信大家最熟悉的就是ListT集合的遍历方式了,那我们就用ListT的示例来演示一下 Listint ints new Listint(); foreach(int item in ints) {Console.WriteLine(item); }上面的这段代码很简单我们也没有给它任何初始化的数据这样可以排除干扰让我们能更清晰的看到反编译的结果排除其他干扰。它反编译后的代码是这样的 Listint list new Listint(); Listint.Enumerator enumerator list.GetEnumerator(); try {while (enumerator.MoveNext()){int current enumerator.Current;Console.WriteLine(current);} } finally {((IDisposable)enumerator).Dispose(); }可以反编译代码的工具有很多我用的比较多的一般是ILSpy、dnSpy、dotPeek和在线c#反编译网站sharplab.io其中dnSpy还可以调试反编译的代码。 通过上面的反编译之后的代码我们可以看到foreach会变编译成一个固定的结构 Enumerator enumerator list.GetEnumerator(); while (enumerator.MoveNext()) {var current enumerator.Current; }通过这段固定的结构我们总结一下foreach的工作原理 可以被foreach的对象需要要包含GetEnumerator()方法迭代器对象包含MoveNext()方法和Current属性MoveNext()方法返回bool类型判断是否可以继续迭代。Current属性返回当前的迭代结果。 我们可以看一下ListT类可迭代的源码结构是如何实现的 public class ListT : IListT, IList, IReadOnlyListT {public Enumerator GetEnumerator() new Enumerator(this);IEnumeratorT IEnumerableT.GetEnumerator() Count 0 ? SZGenericArrayEnumeratorT.Empty : GetEnumerator();IEnumerator IEnumerable.GetEnumerator() ((IEnumerableT)this).GetEnumerator();public struct Enumerator : IEnumeratorT, IEnumerator{public T Current _current!;public bool MoveNext(){}} }这里涉及到了两个核心的接口IEnumerable和IEnumerator他们两个定义了可以实现迭代的能力抽象实现方式如下 public interface IEnumerable {IEnumerator GetEnumerator(); }public interface IEnumerator {bool MoveNext();object Current{ get; }void Reset(); }如果类实现IEnumerable接口并实现了GetEnumerator()方法便可以被foreach迭代的对象是IEnumerator类型包含可MoveNext()方法和Current属性。上面的接口是原始对象的方式这种操作都是针对object类型集合对象。我们实际开发过程中大多数都是使用的泛型集合当然也有对应的实现方式如下所示 public interface IEnumerableout T : IEnumerable {new IEnumeratorT GetEnumerator(); }public interface IEnumeratorout T : IDisposable, IEnumerator {new T Current{ get; } }可以被foreach迭代并不意味着一定要去实现IEnumerable接口这只是给我们提供了一个可以被迭代的抽象的能力。只要类中包含GetEnumerator()方法并返回一个迭代器迭代器里包含返回bool类型的MoveNext()方法和获取当前迭代对象的Current属性即可。 yield return本质 上面我们看到了可以被foreach迭代的本质是什么那么yield return的返回值可以被IEnumerableT接收说明其中必有蹊跷我们反编译一下我们上面的示例看一下反编译之后代码为了方便大家对比反编译结果这里我把上面的示例再次粘贴一下 foreach (var num in GetInts()) {Console.WriteLine(外部遍历了:{0}, num); }IEnumerableint GetInts() {for (int i 0; i 5; i){Console.WriteLine(内部遍历了:{0}, i);yield return i;} }它的反编译结果这里咱们就不全部展示了只展示一下核心的逻辑 //foeach编译后的结果 IEnumeratorint enumerator GetInts().GetEnumerator(); try {while (enumerator.MoveNext()){int current enumerator.Current;Console.WriteLine(外部遍历了:{0}, current);} } finally {if (enumerator ! null){enumerator.Dispose();} }//GetInts方法编译后的结果 private IEnumerableint GetInts() {GetIntsd__1 GetIntsd__ new GetIntsd__1(-2);GetIntsd__.4__this this;return GetIntsd__; }这里我们可以看到GetInts()方法里原来的代码不见了而是多了一个GetIntsd__1 l类型也就是说yield return本质是语法糖。我们看一下GetIntsd__1类的实现 //生成的类即实现了IEnumerable接口也实现了IEnumerator接口 //说明它既包含了GetEnumerator()方法也包含MoveNext()方法和Current属性 private sealed class GetIntsd__1 : IEnumerableint, IEnumerable, IEnumeratorint, IEnumerator, IDisposable {private int 1__state;//当前迭代结果private int 2__current;private int l__initialThreadId;public C 4__this;private int i5__1;//当前迭代到的结果int IEnumeratorint.Current{get{ return 2__current; }}//当前迭代到的结果object IEnumerator.Current{get{ return 2__current; }}//构造函数包含状态字段变向说明靠状态机去实现核心流程流转public GetIntsd__1(int 1__state){this.1__state 1__state;l__initialThreadId Environment.CurrentManagedThreadId;}//核心方法MoveNextprivate bool MoveNext(){int num 1__state;if (num ! 0){if (num ! 1){return false;}//控制状态1__state -1;//自增 也就是代码里循环的ii5__1;}else{1__state -1;i5__1 0;}//循环终止条件 上面循环里的i5if (i5__1 5){Console.WriteLine(内部遍历了:{0}, i5__1);//把当前迭代结果赋值给Current属性2__current i5__1;1__state 1;//说明可以继续迭代return true;}//迭代结束return false;}//IEnumerator的MoveNext方法bool IEnumerator.MoveNext(){return this.MoveNext();}//IEnumerable的IEnumerable方法IEnumeratorint IEnumerableint.IEnumerable(){//实例化GetIntsd__1实例GetIntsd__1 GetIntsd__;if (1__state -2 l__initialThreadId Environment.CurrentManagedThreadId){1__state 0;GetIntsd__ this;}else{//给状态机初始化GetIntsd__ new GetIntsd__1(0);GetIntsd__.4__this 4__this;}//因为GetIntsd__1实现了IEnumerator接口所以可以直接返回return GetIntsd__;}IEnumerator IEnumerable.GetEnumerator(){//因为GetIntsd__1实现了IEnumerator接口所以可以直接转换return ((IEnumerableint)this).GetEnumerator();}void IEnumerator.Reset(){}void IDisposable.Dispose(){} }通过它生成的类我们可以看到该类即实现了IEnumerable接口也实现了IEnumerator接口说明它既包含了GetEnumerator()方法也包含MoveNext()方法和Current属性。用这一个类就可以满足可被foeach别带的核心结构。我们手动写的for代码被包含到了MoveNext()方法里它包含了定义的状态机制代码并且根据当前的状态机代码将迭代移动到下一个元素。我们大概讲解一下我们的for代码被翻译到MoveNext()方法里的执行流程 首次迭代时1__state被初始化成0代表首个被迭代的元素这个时候Current初始值为0循环控制变量i5__1初始值也为0。判断是否满足终止条件不满足则执行循环里的逻辑。并更改装填机1__state为1代表首次迭代执行完成。循环控制变量i5__1继续自增并更改并更改装填机1__state为-1代表可持续迭代。并循环执行循环体的自定义逻辑。不满足迭代条件则返回false,也就是代表了MoveNext()以不满足迭代条件while (enumerator.MoveNext())逻辑终止。 上面我们还展示了另一种yield return的方式就是同一个方法里包含多个yield return的形式 IEnumerableint GetInts() {Console.WriteLine(内部遍历了:0);yield return 0;Console.WriteLine(内部遍历了:1);yield return 1;Console.WriteLine(内部遍历了:2);yield return 2; }上面这段代码反编译的结果如下所示这里咱们只展示核心的方法MoveNext()的实现 private bool MoveNext() {switch (1__state){default:return false;case 0:1__state -1;Console.WriteLine(内部遍历了:0);2__current 0;1__state 1;return true;case 1:1__state -1;Console.WriteLine(内部遍历了:1);2__current 1;1__state 2;return true;case 2:1__state -1;Console.WriteLine(内部遍历了:2);2__current 2;1__state 3;return true;case 3:1__state -1;return false;} }通过编译后的代码我们可以看到多个yield return的形式会被编译成switch...case的形式有几个yield return则会编译成n1个case多出来的一个case则代表的MoveNext()终止条件也就是返回false的条件。其它的case则返回true表示可以继续迭代。 IAsyncEnumerable接口 上面我们展示了同步yield return方式c# 8开始新增了IAsyncEnumerableT接口用于完成异步迭代也就是迭代器逻辑里包含异步逻辑的场景。IAsyncEnumerableT接口的实现代码如下所示 public interface IAsyncEnumerableout T {IAsyncEnumeratorT GetAsyncEnumerator(CancellationToken cancellationToken default); }public interface IAsyncEnumeratorout T : IAsyncDisposable {ValueTaskbool MoveNextAsync();T Current { get; } }它最大的不同则是同步的IEnumerator包含的是MoveNext()方法返回的是boolIAsyncEnumerator接口包含的是MoveNextAsync()异步方法返回的是ValueTaskbool类型。所以上面的示例代码 await foreach (var num in GetIntsAsync()) {Console.WriteLine(外部遍历了:{0}, num); }所以这里的await虽然是加在foreach上面但是实际作用的则是每一次迭代执行的MoveNextAsync()方法。可以大致理解为下面的工作方式 IAsyncEnumeratorint enumerator list.GetAsyncEnumerator(); while (enumerator.MoveNextAsync().GetAwaiter().GetResult()) {var current enumerator.Current; }当然实际编译成的代码并不是这个样子的我们在之前的文章研究c#异步操作async await状态机的总结一文中讲解过async await会被编译成IAsyncStateMachine异步状态机所以IAsyncEnumeratorT结合yield return的实现比同步的方式更加复杂而且包含更多的代码不过实现原理可以结合同步的方式类比一下但是要同时了解异步状态机的实现这里咱们就不过多展示异步yield return的编译后实现了有兴趣的同学可以自行了解一下。 foreach增强 c# 9增加了对foreach的增强的功能即通过扩展方法的形式对原本具备包含foreach能力的对象增加GetEnumerator()方法使得普通类在不具备foreach的能力的情况下也可以使用来迭代。它的使用方式如下 Foo foo new Foo(); foreach (int item in foo) {Console.WriteLine(item); }public class Foo {public Listint Ints { get; set; } new Listint(); }public static class Bar {//给Foo定义扩展方法public static IEnumeratorint GetEnumerator(this Foo foo){foreach (int item in foo.Ints){yield return item;}} }这个功能确实比较强大满足开放封闭原则我们可以在不修改原始代码的情况增强代码的功能可以说是非常的实用。我们来看一下它的编译后的结果是啥 Foo foo new Foo(); IEnumeratorint enumerator Bar.GetEnumerator(foo); try {while (enumerator.MoveNext()){int current enumerator.Current;Console.WriteLine(current);} } finally {if (enumerator ! null){enumerator.Dispose();} }这里我们看到扩展方法GetEnumerator()本质也是语法糖会把扩展能力编译成扩展类.GetEnumerator(被扩展实例)的方式。也就是我们写代码时候的原始方式只是编译器帮我们生成了它的调用方式。接下来我们看一下GetEnumerator()扩展方法编译成了什么 public static IEnumeratorint GetEnumerator(Foo foo) {GetEnumeratord__0 GetEnumeratord__ new GetEnumeratord__0(0);GetEnumeratord__.foo foo;return GetEnumeratord__; }看到这个代码是不是觉得很眼熟了不错和上面yield return本质这一节里讲到的语法糖生成方式是一样的了同样的编译时候也是生成了一个对应类这里的类是GetEnumeratord__0,我们看一下该类的结构 private sealed class GetEnumeratord__0 : IEnumeratorint, IEnumerator, IDisposable {private int 1__state;private int 2__current;public Foo foo;private Listint.Enumerator s__1;private int item5__2;int IEnumeratorint.Current{get{ return 2__current; }}object IEnumerator.Current{get{ return 2__current; }}public GetEnumeratord__0(int 1__state){this.1__state 1__state;}private bool MoveNext(){try{int num 1__state;if (num ! 0){if (num ! 1){return false;}1__state -3;}else{1__state -1;//因为示例中的Ints我们使用的是ListTs__1 foo.Ints.GetEnumerator();1__state -3;}//因为上面的扩展方法里使用的是foreach遍历方式//这里也被编译成了实际生产方式if (s__1.MoveNext()){item5__2 s__1.Current;2__current item5__2;1__state 1;return true;}m__Finally1();s__1 default(Listint.Enumerator);return false;}catch{((IDisposable)this).Dispose();throw;}}bool IEnumerator.MoveNext(){return this.MoveNext();}void IDisposable.Dispose(){}void IEnumerator.Reset(){}private void m__Finally1(){} }看到编译器生成的代码我们可以看到yield return生成的代码结构都是一样的只是MoveNext()里的逻辑取决于我们写代码时候的具体逻辑不同的逻辑生成不同的代码。这里咱们就不在讲解它生成的代码了因为和上面咱们讲解的代码逻辑是差不多的。 总结 通过本文我们介绍了c#中的yield return语法并探讨了由它带来的一些思考。我们通过一些简单的例子展示了yield return的使用方式知道了迭代器来是如何按需处理大量数据。同时我们通过分析foreach迭代和yield return语法的本质讲解了它们的实现原理和底层机制。好在涉及到的知识整体比较简单仔细阅读相关实现代码的话相信会了解背后的实现原理这里就不过多赘述了。 当你遇到挑战和困难时请不要轻易放弃。无论你面对的是什么只要你肯努力去尝试去探索去追求你一定能够克服困难走向成功。记住成功不是一蹴而就的它需要我们不断努力和坚持。相信自己相信自己的能力相信自己的潜力你一定能够成为更好的自己。
http://www.ho-use.cn/article/10818985.html

相关文章:

  • 行业网站设计开发费用深圳品牌设计公司有哪些
  • 网站右侧二维码广东新闻频道直播
  • 如何登陆网站空间关于wordpress自动更新
  • 网站平台建设方案策划书凡客诚品图片
  • 阿里云服务器可以做网站网站宣传怎样做不违法
  • 天津技术网站建设电脑网站搜索如何做
  • 网站建设合同验收标准全国为何又突然做核酸了
  • 网站建设的意义以及重要性国内做五金加工的订单网站
  • 螺旋钢管网站建设网站后台验证码出不来
  • ps里新建网站尺寸怎么做医院做网站需要备案吗
  • 建材建设网站大连市房屋管理局官方网站
  • 宝安网站推广动易与php环境架设网站
  • 泰州网站建设价格服装公司网站模板
  • 交互做的好的中国网站百度做网站联系电话
  • 建立网站怎么做关键字网络培训的感受
  • 目前比较新的网站建设技术做网站需要购买什么
  • 免费x网站域名wordpress 分类选模板
  • wordpress 视频站模板宁波优化推广
  • 网站平台构建网络推广文案有哪些
  • 做游戏直播什么游戏视频网站月子会所 网站源码
  • 汕头个人建站模板域名和网站空间相互做解析
  • 中文网站域名注册制作企业网站的新闻显示
  • 西峡微网站开发软件开发外包网
  • 南岸集团网站建设域名解析好了怎么做网站
  • 广州公司网站设计一块钱涨1000粉网站
  • 免费空间网站网站互联网接入商
  • 郴州58网站宝塔搭建wordpress网站
  • p2p网上贷款网站建设方案.docxwordpress通用型大气简洁企业主题
  • 镇江建设质量监督站网站云建站淘宝客
  • 网站免费优化软件好用的h5网站模板下载