C# 索引器,实现IEnumerable接口的GetEnumerator()方法

时间:2022-01-30 21:02:46

当自定义类需要实现索引时,可以在类中实现索引器。

用Table作为例子,Table由多个Row组成,Row由多个Cell组成,

我们需要实现自定义的table[0],row[0]

索引器定义格式为

[修饰符] 数据类型 this[索引类型 index]

以下是代码

     /// <summary>
/// 单元格
/// </summary>
public class Cell
{
/// <summary>
/// Value
/// </summary>
public object Value { get; set; }
/// <summary>
/// StringValue
/// </summary>
public string StringValue { get; set; }
}
     /// <summary>
/// 行
/// </summary>
public class Row
{
/// <summary>
/// cells
/// </summary>
private Cell[] _cells; /// <summary>
/// 获取Row中的Cell数
/// </summary>
public int Length { get; private set; } /// <summary>
/// 索引
/// </summary>
public Cell this[int column]
{
get
{
return this[column];
}
}
/// <summary>
/// 行
/// </summary>
/// <param name="values"></param>
public Row(object[] values)
{
this.Length = values.Length;
this._cells = new Cell[this.Length];
for (int i = ; i < this.Length; i++)
{
_cells[i].Value = values[i];
_cells[i].StringValue = Convert.ToString(values[i]);
}
}
/// <summary>
/// 行
/// </summary>
/// <param name="values"></param>
public Row(string[] values)
{
this.Length = values.Length;
this._cells = new Cell[this.Length];
for (int i = ; i < this.Length; i++)
{
_cells[i].Value = values[i];
_cells[i].StringValue = values[i];
}
}
/// <summary>
/// 行
/// </summary>
/// <param name="values"></param>
public Row(int[] values)
{
this.Length = values.Length;
this._cells = new Cell[this.Length];
for (int i = ; i < this.Length; i++)
{
_cells[i].Value = values[i];
_cells[i].StringValue = values[i].ToString();
}
}
}

这时候,Row就可以有自己的索引了,调用如下

     public class Test
{
public Test()
{
Row row = new Row(new string[] { "姓名", "性别", "工号" });
if (row.Length > )
{
row[].StringValue = "学号";
}
}
}

但是,Row虽然作为一个Cell的集合,却不能使用foreach进行遍历。这时候我们需要让Row继承IEnumerable接口,并且实现IEnumerable接口的GetEnumerator()方法,

在public class Row : IEnumerable { }中添加如下代码:

         /// <summary>
/// 实现GetEnumerator()方法
/// </summary>
/// <returns></returns>
public IEnumerator GetEnumerator()
{
for (int i = ; i < this.Length; i++)
{
yield return this[i];
}
}

这样,在调用的时候就能使用foreach遍历了。
Table和Row的关系同理。

同样,我们还可以继承ICollection<T>, IEnumerable<T>, IList<T>等接口,实现相关接口的方法,就可以打造属于自己的集合了。

一个完整的Demo如下:

 using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text; namespace MyCollection
{
/// <summary>
/// 表示 Cell 集合
/// </summary>
[DebuggerDisplay("Count = {Count}")]
[Serializable]
public class MyCollection : IEnumerable, IEnumerable<Cell>, ICollection<Cell>, IList<Cell>
{
#region 字段 /// <summary>
/// 表示空的 Row 图层的数组。
/// </summary>
private readonly static Row[] emptyArray = null; /// <summary>
/// 存储 Row 图层的数组。
/// </summary>
private Row[] items = null; /// <summary>
/// 当前 Row 图层的集合的元素数。
/// </summary>
private int count = ; #endregion #region 属性 /// <summary>
/// 获取或设置该 Row 的元素总数。
/// </summary>
/// <exception cref="System.ArgumentOutOfRangeException">MyCollection.Capacity 设置为小于 MyCollection.Count 的值。</exception>
private int Capacity
{
get
{
return this.items.Length;
}
set
{
if (value != this.items.Length)
{
if (value < this.count)
{
throw new ArgumentOutOfRangeException("Capacity", "MyCollection.Capacity 设置为小于 MyCollection.Count 的值。");
}
if (value > )
{
Row[] destArray = new Row[value];
if (this.count > )
{
Array.Copy(this.items, , destArray, , this.count);
}
this.items = destArray;
}
else
{
this.items = emptyArray;
}
}
}
} #endregion #region 构造函数
/// <summary>
/// 对 LayerCollection 类进行初始化。
/// </summary>
static MyCollection()
{
emptyArray = new Row[];
} /// <summary>
/// 初始化 HuaXing.ExamOperation.SimulateFlash.LayerCollection 类的新实例。<para/>
/// 表示 Layer 图层的集合。
/// </summary>
public MyCollection()
{
this.items = emptyArray;
}
#endregion #region IList<Row> 成员 #region IndexOf /// <summary>
/// 搜索指定的 Row 对象,并返回整个 MyCollection 中第一个匹配项的从零开始的索引。
/// </summary>
/// <param name="item">要在 MyCollection 中定位的 Row 对象。</param>
/// <returns>如果在 MyCollection 中找到 item 的第一个匹配项,则为该项的从零开始的索引;否则为-1。</returns>
public int IndexOf(Row item)
{
return Array.IndexOf<Row>(this.items, item, , this.count);
} /// <summary>
/// 搜索指定的 Row 对象,并返回整个 MyCollection 中从指定索引到最后一个元素的元素范围内第一个匹配项的从零开始的索引。
/// </summary>
/// <param name="item">要在 MyCollection 中定位的 Row 对象。</param>
/// <param name="index">从零开始的搜索的起始索引。</param>
/// <returns>如果在 MyCollection 中从 index 到最后一个元素的元素范围内找到 item 的第一个匹配项,则为该项的从零开始的索引;否则为-1。</returns>
/// <exception cref="System.ArgumentOutOfRangeException">index 不在 MyCollection 的有效索引范围内。</exception>
public int IndexOf(Row item, int index)
{
if (index < || index > this.count)
{
throw new ArgumentOutOfRangeException("index", "index 不在 MyCollection 的有效索引范围内。");
}
return Array.IndexOf<Row>(this.items, item, index, this.count - index);
} /// <summary>
/// 搜索指定的 Row 对象,并返回整个 MyCollection 中从指定的索引开始并包含指定的元素数的元素范围内第一个匹配项的从零开始的索引。
/// </summary>
/// <param name="item">要在 MyCollection 中定位的 Row 对象。</param>
/// <param name="index">从零开始的搜索的起始索引。</param>
/// <param name="count">要搜索的部分中的元素数。</param>
/// <returns>如果在 MyCollection 中从 index 开始并包含 count 个元素的元素范围内找到 item 的第一个匹配项,则为该项的从零开始的索引;否则为-1。</returns>
/// <exception cref="System.ArgumentOutOfRangeException">index 不在 MyCollection 的有效索引范围内 或 count 小于 0 或 index 和 count 未指定 MyCollection 中的有效部分。</exception>
public int IndexOf(Row item, int index, int count)
{
if (index < || index > this.count)
{
throw new ArgumentOutOfRangeException("index", "index 不在 MyCollection 的有效索引范围内。");
}
if ((count < ) || (index > (this.count - count)))
{
throw new ArgumentOutOfRangeException("count", "count 小于 0 或 index 和 count 未指定 MyCollection 中的有效部分。");
}
return Array.IndexOf<Row>(this.items, item, index, count);
} #endregion #region Insert /// <summary>
/// 将 Row 对象插入 MyCollection 的指定索引处。
/// </summary>
/// <param name="index">从零开始的索引,应在该位置插入 item。</param>
/// <param name="item">要插入的 Row 对象。</param>
/// <exception cref="System.ArgumentOutOfRangeException">index 小于 0 或 index 大于 MyCollection.Count。</exception>
public void Insert(int index, Row item)
{
if (index < || index > this.count)
{
throw new ArgumentOutOfRangeException("index", "index 小于 0 或 index 大于 MyCollection.Count。");
}
if (this.count == this.items.Length)
{
this.EnsureCapacity(this.count + );
}
if (index < this.count)
{
Array.Copy(this.items, index, this.items, index + , this.count - index);
}
this.items[index] = item;
this.count++;
} #endregion #region RemoveAt /// <summary>
/// 移除 MyCollection 的指定索引处的 Row 对象。
/// </summary>
/// <param name="index">要移除的 Row 对象的从零开始的索引。</param>
/// <exception cref="System.ArgumentOutOfRangeException">index 小于 0 或 index 等于或大于 MyCollection.Count。</exception>
public void RemoveAt(int index)
{
if (index < || index >= this.count)
{
throw new ArgumentOutOfRangeException("index", "index 小于 0 或 index 等于或大于 MyCollection.Count。");
}
this.count--;
if (index < this.count)
{
Array.Copy(this.items, index + , this.items, index, this.count - index);
}
this.items[this.count] = default(Row);
} #endregion #region Item[Int32] /// <summary>
/// 获取或设置指定索引处的 Row 对象。
/// </summary>
/// <param name="index">要获取或设置的 Row 对象从零开始的索引。</param>
/// <returns>指定索引处的 Row 对象。</returns>
/// <exception cref="System.ArgumentOutOfRangeException">index 小于 0 或 index 等于或大于 MyCollection.Count。</exception>
public Row this[int index]
{
get
{
if (index < && index >= this.count)
{
throw new ArgumentOutOfRangeException("index", "index 小于 0 或 index 等于或大于 MyCollection.Count。");
}
else
{
return this.items[index];
}
}
set
{
if (index < && index >= this.count)
{
throw new ArgumentOutOfRangeException("index", "index 小于 0 或 index 等于或大于 MyCollection.Count。");
}
else
{
this.items[index] = value;
}
}
} #endregion #endregion #region ICollection<Row> 成员 #region Add /// <summary>
/// 将 Row 对象,添加到 MyCollection 的结尾处。
/// </summary>
/// <param name="item">要添加到 MyCollection 的末尾处的 Row 对象。</param>
public void Add(Row item)
{
if (this.count == this.items.Length)
{
this.EnsureCapacity(this.count + );
}
this.items[this.count++] = item;
} #endregion #region Clear /// <summary>
/// 从 MyCollection 集合中移除所有元素。
/// </summary>
public void Clear()
{
if (this.count > )
{
Array.Clear(this.items, , this.count);
this.count = ;
}
} #endregion #region Contains /// <summary>
/// 确定 MyCollection 集合中,是否包含特定值。
/// </summary>
/// <param name="value">要在 MyCollection 集合中查找的 Row。</param>
/// <returns>如果在 MyCollection 集合中找到 Row,则为true;否则为false。</returns>
public bool Contains(Row value)
{
if (value == null)
{
for (int j = ; j < this.count; j++)
{
if (this.items[j] == null)
{
return true;
}
}
return false;
}
EqualityComparer<Row> comparer = EqualityComparer<Row>.Default;
for (int i = ; i < this.count; i++)
{
if (comparer.Equals(this.items[i], value))
{
return true;
}
}
return false;
} #endregion #region CopyTo /// <summary>
/// 将整个 MyCollection 复制到一维数组中,从目标数组的开头开始放置。
/// </summary>
/// <param name="array">作为从 MyCollection 复制的元素的目标位置的一维数组。</param>
/// <exception cref="System.ArgumentException">源 MyCollection 中的元素数大于目标 array 可包含的元素数。</exception>
/// <exception cref="System.ArgumentNullException">array 为 null。</exception>
public void CopyTo(Row[] array)
{
this.CopyTo(array, );
} /// <summary>
/// 将整个 MyCollection 复制到一维数组中,从目标数组的指定索引位置开始放置。
/// </summary>
/// <param name="array">作为从 MyCollection 复制的元素的目标位置的一维数组。</param>
/// <param name="arrayIndex">array 中从零开始的索引,在此处开始复制。</param>
/// <exception cref="System.ArgumentException">arrayIndex 等于或大于 array 的长度 或 源 MyCollection 中的元素数目大于从 arrayIndex 到目标 array 末尾之间的可用空间。</exception>
/// <exception cref="System.ArgumentNullException">array 为 null。</exception>
/// <exception cref="System.ArgumentOutOfRangeException">arrayIndex 小于 0。</exception>
public void CopyTo(Row[] array, int arrayIndex)
{
Array.Copy(this.items, , array, arrayIndex, this.count);
} /// <summary>
/// 将一定范围的元素从 MyCollection 复制到一维数组中,从目标数组的指定索引位置开始放置。
/// </summary>
/// <param name="index">源 MyCollection 中复制开始位置的从零开始的索引。</param>
/// <param name="array">作为从 MyCollection 复制的元素的目标位置的一维数组。</param>
/// <param name="arrayIndex">array 中从零开始的索引,在此处开始复制。</param>
/// <param name="count">要复制的元素数。</param>
/// <exception cref="System.ArgumentException">index 等于或大于源 MyCollection 的 MyCollection.Count 或 arrayIndex 等于或大于 array 的长度 或 从 index 到源 MyCollection 的末尾的元素数大于从 arrayIndex 到目标 array 的末尾的可用空间。</exception>
/// <exception cref="System.ArgumentNullException">array 为 null。</exception>
/// <exception cref="System.ArgumentOutOfRangeException">index 小于 0 或 arrayIndex 小于 0 或 count 小于 0。</exception>
public void CopyTo(int index, Row[] array, int arrayIndex, int count)
{
if ((this.count - index) < count)
{
throw new ArgumentException("index 等于或大于源 MyCollection 的 MyCollection.Count 或 arrayIndex 等于或大于 array 的长度 或 从 index 到源 MyCollection 的末尾的元素数大于从 arrayIndex 到目标 array 的末尾的可用空间。", "index");
}
Array.Copy(this.items, index, array, arrayIndex, count);
} #endregion #region Count /// <summary>
/// 获取当前 Row 集合的元素数。
/// </summary>
public int Count
{
get
{
return this.count;
}
} #endregion #region IsReadOnly /// <summary>
/// 获取一个值,该值指示 MyCollection 是否为只读。
/// </summary>
bool ICollection<Row>.IsReadOnly
{
get
{
return false;
}
} #endregion #region Remove /// <summary>
/// 从 MyCollection 中移除特定 Row 对象的第一个匹配项。
/// </summary>
/// <param name="item">要从 MyCollection 中移除的 Row 对象。</param>
/// <returns>如果成功移除 item,则为 true;否则为 false。如果在 MyCollection 中没有找到 item,该方法也会返回 false。</returns>
public bool Remove(Row item)
{
int index = this.IndexOf(item);
if (index >= )
{
this.RemoveAt(index);
return true;
}
return false;
} #endregion #endregion #region IEnumerable<Row> 成员 public IEnumerator<Row> GetEnumerator()
{
for (int index = ; index < this.count; index++)
{
yield return this.items[index];
}
} #endregion #region IEnumerable 成员 IEnumerator IEnumerable.GetEnumerator()
{
for (int index = ; index < this.count; index++)
{
yield return this.items[index];
}
} #endregion #region 辅助方法 /// <summary>
/// 确保当前集合的容量,不小于指定的值。
/// </summary>
/// <param name="min">指定一个值,此方法会确保当前集合的容量不小于此值。</param>
private void EnsureCapacity(int min)
{
if (this.items.Length < min)
{
int num = this.items.Length;
if (num < min)
{
num = min;
}
this.Capacity = num;
}
}
#endregion
}
}