.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]);
}
越是无知的人越是觉得自己无所不知(之前的自己)
越是学习的人越是觉得自己会的太少了(现在的自己)
共勉