.NET/Js 迭代器(手撕源码)

概念

迭代器模式

描述:迭代器模式是 java 和 .NET 编程环境中非常常用的设计模式。这种模式用于顺序访问集合对象的元素,不需要知道集合对象的元素,不需要知道集合对象的底层细节。

  • 意图: 提供一种方法可以顺序的访问聚合对象中的各个元素,不需要知道集合对象的底层细节
  • 何时使用: 遍历一个集合对象
  • 目标: 把元素之间游走的责任交给迭代器,而不是聚合对象本身

.NET 迭代器模式

1.预热

新建一个项目Iterator.Console
创建一个SqlHelper类,如下:

点击查看代码
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Data.SqlClient;
using Oracle.ManagedDataAccess.Client;

namespace Iterator.Console
{
	public class SqlHelper
	{
		public static void GetData()
		{
			using (SqlConnection conn = new SqlConnection("Server=101.23.259.68,1433;database=testDb;uid=sa;pwd=123456"))
			{
				conn.Open();
				SqlCommand cmd = new SqlCommand("select * from TEST1", conn);
				SqlDataReader reader = cmd.ExecuteReader();
				do
				{
					while (reader.Read())
					{
						string DAINPU = reader["DAINPU"].ToString();
						System.Console.WriteLine(DAINPU);
					}
				} while (reader.NextResult());
			}


		}
	}
}

JS迭代器模式

代码如下:

Iterator.js
//迭代器
class Iterator {
  constructor(container) {
    this.list = container.list
    this.index = 0
  }
  hasNext() {
    if (this.index >= this.list.length) {
      return false
    } else {
      return true
    }
  }
  next() {
    if (this.hasNext) {
      return this.list[this.index++]
    }
    return null
  }
}
//可迭代
class Iteratable {
  constructor(list) {
    this.list = list
  }
  getIterator() {
    return new Iterator(this)
  }
}
let iteratable = new Iteratable([1, 2, 3, 4, 5, 6])
let iterator = iteratable.getIterator()
while (iterator.hasNext()) {
  console.log(iterator.next())
}

js代码很简单,简单说一下思路
基本原理就是新建一个可迭代的对象,构造函数中塞入一个数组,创建一个list集合。
创建一个获取迭代器对象,返回迭代器对象,这个迭代器对象构造函数传参需要一个容器,直接返回当前可迭代对象,
迭代器构造函数中处理,获取当前list集合,创建index索引,默认值为0。
创建一个判断当前数组是否还有下一个值的方法,如果当前索引大于等于当前数组的长度,则返回false,反之返回true。
创建一个获取数组中下一个值的方法,调用获取数组是否有下一个值的方法,如果返回true,则返回数组中下一个值,如果没有返回null
大体思路就是这样

C# 迭代器

代码与js基本一致,就是将js的类抽象成接口,
创建一个 Iterator.Console 控制台项目

1.创建IIterator(迭代器) 接口

点击查看代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Iterator.Console
{
	public interface IIterator
	{
		object Next();
		bool HasNext();
	}
}

2.新建一个接口(Iteratable 可迭代对象):

Iteratable
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Iterator.Console
{
	public class Iteratable : IIteratable
	{
		public object this[int index] { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }

		int IIteratable.Count => throw new NotImplementedException();
		public IIterator GetIterator()
		{
			return new Iterator(this);
		}
	}
}

3.创建IIterator 实现对象

Iterator
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Iterator.Console
{
	public class Iterator : IIterator
	{
		//readonly 对属性没用,会报错
		private readonly IIteratable Iteratable;
		/// <summary>
		/// 当前下标
		/// </summary>
		private int current = 0;
		public Iterator(IIteratable iteratable)
		{
			this.Iteratable = iteratable;

		}
		public bool HasNext()
		{
			// Iteratable[]
			return current < Iteratable.Count;
		}

		public object Next()
		{
			if (HasNext())
			{
				return Iteratable[current++];
			}
			else
			{
				return null;
			}
		}
	}
}

4.创建 Iteratable 对象

Iteratable
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Iterator.Console
{
	public class Iteratable : IIteratable
	{
		/// List<T> ArrayList List<object> T[] object[] 区别
		/// ArrayList ≈ List<object> ArrayList是一个可变数组
		private IList<object> items = new List<object>();
		public object this[int index] { get => items[index]; set => items.Insert(index, value); }

		int IIteratable.Count => items.Count();
		public IIterator GetIterator()
		{
			return new Iterator(this);
		}
	}
}

5.调用方式如下:

点击查看代码
// See https://aka.ms/new-console-template for more information
using Iterator.Console;

// Console.WriteLine("Hello, World!");
// SqlHelper.GetData();//1
var iteratable = new Iteratable();
iteratable[0] = 1;
iteratable[1] = 2;
iteratable[2] = 3;
var iterator = iteratable.GetIterator();
while (iterator.HasNext())
{
	System.Console.WriteLine(iterator.Next());
}

基础的迭代器模式完结,下面开始手写源码
--------------------------2022-08-21------------------
加班加麻了。赶紧熬到十月份吧

源码

1.创建一个IAceList的接口

记住:一个接口中,this 作为属性的话,有get和set方法,就是一个索引器

IAceList
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Iterator.Console.AceList
{
	public interface IAceList<T>
	{
		/// <summary>
		/// 索引器
		/// </summary>
		/// <value></value>
		T this[int index] { get; }
		/// <summary>
		/// list集合的长度
		/// </summary>
		/// <value></value>
		int Count { get; }
		/// <summary>
		/// list集合的添加方法
		/// </summary>
		/// <param name="item"></param>
		void Add(T item);
		/// <summary>
		/// list集合的insert方法
		/// </summary>
		/// <param name="index"></param>
		/// <param name="item"></param>
		void Insert(int index, T item);
		/// <summary>
		/// list集合的remove 方法
		/// </summary>
		/// <param name="item"></param>
		void Remove(T item);
		/// <summary>
		/// list删除某个下标的值的方法
		/// </summary>
		/// <param name="index"></param>
		void RemoveAt(int index);
		/// <summary>
		/// 清空list集合的所有值
		/// </summary>
		void Clear();

		int IndexOf(T item);

		bool Contains(T item);
		T[] ToArray();
	}
}

2.AceList实现代码如下:

点击查看代码
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading.Tasks;

namespace Iterator.Console.AceList
{
	[DebuggerDisplay("Count={Count}")]
	[DebuggerTypeProxy(typeof(AceListView<>))]
	public class AceList<T> : IAceList<T>, IEnumerable<T>, IEnumerable
	{
		private T[] _items;
		public T this[int index] { get => _items[index]; }
		private int _count;
		public int Count => _count;
		public AceList()
		{
			/// <summary>
			/// 初始化集合,因为集合初始化是有四个长度的,所以初始化四个长度
			/// </summary>
			_items = new T[0];
		}
		public void Add(T item)
		{
			//判断当前数组中的数量大于数组的长度
			if (_count >= _items.Length)
			{
				//则重新设置数组长度
				SetSize();
			}
			_items[_count] = item;
			_count++;
		}
		private int Size
		{
			get => _items.Length;
			set
			{
				if (value < _count)
				{
					throw new Exception("");
				}
				if (value != _items.Length)
				{
					if (value > 0)
					{
						//创建一个新数组
						T[] newArray = new T[value];
						//把老数组拷贝给新数组
						if (_count > 0)
						{
							Array.Copy(_items, newArray, _count);
						}
						//用新数组覆盖原有数组
						_items = newArray;
					}
					else
					{
						_items = new T[0];
					}
				}
			}
		}
		/// <summary>
		/// 重新设置数组的长度
		/// </summary>
		private void SetSize()
		{
			//如果初始数组的长度为0,则赋4,否则在当前长度上*2
			int newSize = _items.Length == 0 ? 4 : _items.Length * 2;
			//健壮性验证,判断传入的value是否小于当前的_count+1
			if (newSize < _count + 1)
			{
				newSize = _count + 1;
			}
			//给Size赋值
			Size = newSize;
		}

		public void Clear()
		{
			// for (int i = 0; i < _count; i++)
			// {
			// 	_items[i] = default; 
			// }
			// _count = 0;
			if (_count > 0)
			{
				Array.Clear(_items, 0, _count);
				_count = 0;
			}
		}

		public void Insert(int index, T item)
		{
			if (index < 0)
			{
				throw new Exception("不能小于0");
			}
			else if (index > Count)
			{
				throw new Exception("不能超过数组的长度");
			}
			for (int i = _count; i > index; i--)
			{
				_items[i] = _items[i - 1];
			}
			_items[index] = item;
			_count++;
		}

		public void Remove(T item)
		{
			for (int i = 0; i < _count; i++)
			{
				//如果要删除的数据和循环到的数据相同,则删除,然后再把链表中的数据向前移动一格
				if (_items[i]!.Equals(item))
				{
					for (int j = i; j < _count - 1; j++)
					{
						_items[j] = _items[j + 1];
					}
					_count--;
					break;
				}
			}
		}

		public void RemoveAt(int index)
		{
			//将要删除的元素右面的数据全部向前移动一格
			if (index < 0)
			{
				throw new Exception("不能小于0");
			}
			else if (index > Count)
			{
				throw new Exception("不能超过数组的长度");
			}
			for (int i = index; i < _count - 1; i++)
			{
				_items[i] = _items[i + 1];
			}
			_count--;
		}

		public int IndexOf(T item)
		{
			int resIndex = -1;
			//初始索引为-1
			for (int i = 0; i < _count; i++)
			{
				if (_items[i].Equals(item))
				{
					resIndex = i;
					break;
				}
			}
			return resIndex;
		}

		public bool Contains(T item)
		{
			int res = IndexOf(item);
			return res > -1;
		}

		public T[] ToArray()
		{
			T[] newArray = new T[_count];
			for (int i = 0; i < _count; i++)
			{
				newArray[i] = _items[i];
			}
			return newArray;
		}

		public IEnumerator<T> GetEnumerator()
		{
			return new MyEnumerator(this);
		}

		IEnumerator IEnumerable.GetEnumerator() => new MyEnumerator(this);
		public class MyEnumerator : IEnumerator<T>
		{
			private AceList<T> _list;
			private int _index;
			[AllowNull, MaybeNull]
			private T _current;
			public T Current => _current;
			public MyEnumerator(AceList<T> list)
			{
				_list = list;
				_index = 0;
				_current = default;
			}
			object IEnumerator.Current => _current;

			public void Dispose()
			{

			}
			/// <summary>
			/// 向后移
			/// </summary>
			/// <returns></returns>
			public bool MoveNext()
			{
				if (_index < _list._count)
				{
					_current = _list._items[_index];
					_index++;
					return true;
				}
				else
				{
					_index = _list._count + 1;
					_current = default;
					return false;
				}
			}

			public void Reset()
			{
				_index = 0;
				_current = default;
			}
		}
	}
}

3.AceListView代码如下:

AceListView
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;

namespace Iterator.Console.AceList
{
	public class AceListView<T>
	{
		private readonly IAceList<T> _aceList;
		public AceListView(IAceList<T> aceList)
		{
			_aceList = aceList;
		}
		[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
		public T[] Items
		{
			get
			{
				T[] items = new T[_aceList.Count];
				for (int i = 0; i < _aceList.Count; i++)
				{
					items[i] = _aceList[i];
				}
				return items;
			}
		}
	}
}

4.调用方法如下:

点击查看代码
// See https://aka.ms/new-console-template for more information
using Iterator.Console;
using Iterator.Console.AceList;

// Console.WriteLine("Hello, World!");
// SqlHelper.GetData();//1
// var iteratable = new Iteratable();
// iteratable[0] = 1;
// iteratable[1] = 2;
// iteratable[2] = 3;
// var iterator = iteratable.GetIterator();
// while (iterator.HasNext())
// {
// 	System.Console.WriteLine(iterator.Next());
// }
var list = new List<string>();
foreach (var item in list)
{

}
AceList<int> acelist = new AceList<int>();
acelist.Add(1);
acelist.Add(2);
acelist.Add(3);
acelist.Add(4);
acelist.Add(5);
acelist.Add(6);
foreach (var item in acelist)
{

}
// acelist.Insert(1, 5);
// acelist.Remove(5);
// acelist.Clear();
var index = acelist.IndexOf(3);
var array = acelist.ToArray();
for (int i = 0; i < acelist.Count; i++)
{
	System.Console.WriteLine(acelist[i]);
}

posted @ 2022-08-23 22:05  rookiexwang  阅读(51)  评论(0编辑  收藏  举报