c#中使用传统[]数组语法的非0数组
本文关键字:数组 语法 传统 | 更新日期: 2023-09-27 18:02:13
我希望能够在c#中创建一个索引范围任意范围的数组,例如,一个索引为100-115的16个元素数组。
c#中的原生数组是基于0的,但我被告知(例如,在Luaan的评论中),c# Array类允许任意的下界和上界。但是在示例中,我看到Array类中的元素是通过myArray.GetValue()和myArray.SetValue()来访问的,而不是像myArray.[ foo ]. 这样的传统数组语法。Array arr = Array.CreateInstance(typeof(string), new[]{16}, new[]{100});
Console.WriteLine(arr.Length); // 16
arr.SetValue("foo", 100);
Console.WriteLine(arr.GetValue(100)); // foo
是否有任何方法可以使数组具有一些任意起始索引,如[100],我可以使用c#中的传统[]语法访问?
你可以创建一个实现装饰器模式的类:只需实现IList接口(也由Array实现),并对this [int index]属性进行任何移动。
装饰器模式描述如下:http://www.codeproject.com/Articles/479635/UnderstandingplusandplusImplementingplusDecoratorp
Array类不支持此操作,但您可以编写自己的索引为1的数组类:
public class OneBasedArray<T>
{
public T[] InnerArray;
public T this[int i]
{
get { return InnerArray[i-1]; }
set { InnerArray[i-1] = value; }
}
}
然后像这样使用:
var myArray = new OneBasedArray<int> { InnerArray = new int[]{ 1, 2, 3, 4, 5 } };
for(int i = 1; i <=5; i++)
{
Console.WriteLine(myArray[i]);
}
这段代码只是为了得到一个想法,这样的类当然需要一个更好的接口。
只有当数组的索引为0时,才能使用数组的索引器
您可以为自定义的非数组类型使用索引器,并使用您想要的任何逻辑,例如使其非零索引,但这不是数组的选项。
我认为Lukas的答案可能是处理这个问题最简单的方法,但是如果,出于某种原因,您真的想使用Array.CreateInstance
(不确定为什么要这样做-也许某些外部库可能会坚持使用它?),您可以将它包装在这样的类中:
public class NonZeroArray<T>
{
private readonly Array array;
public T this[int i]
{
get { return (T)array.GetValue(i); }
set { array.SetValue(value, i); }
}
public NonZeroArray(int length, int lowerBounds = 0)
{
array = Array.CreateInstance(typeof(T), new int[] { length}, new int[] { lowerBounds } );
}
}
显然,你可以让它实现IList<T>
的其余部分,使它更漂亮(更容易使用)。如果你真的需要原生数组,你可以实现一个带有getter的属性,以便在需要的时候公开它。
使用它很简单:
var myNonZeroArray = new NonZeroArray<string>(16,100);
myNonZeroArray[100] = "foo";
Console.WriteLine(myNonZeroArray[100]); // prints "foo"
这是一个扩展IList<T>
的自定义类,以提供从非零索引开始的功能:
public class NonZeroList<T> : IList<T>
{
private int startIndex;
private List<T> inner;
public NonZeroList(int startIndex, IEnumerable<T> content)
{
this.startIndex = startIndex;
inner = content.ToList();
}
public NonZeroList(int startIndex)
{
this.startIndex = startIndex;
inner = new List<T>();
}
public T this[int i]
{
get
{
return inner[i - startIndex];
}
set
{
inner[i - startIndex] = value;
}
}
public IEnumerator<T> GetEnumerator()
{
foreach (T i in inner)
yield return i;
yield break;
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return inner.GetEnumerator();
}
public int IndexOf(T item)
{
return inner.IndexOf(item) + startIndex;
}
public void Insert(int index, T item)
{
inner.Insert(index - startIndex, item);
}
public void RemoveAt(int index)
{
inner.RemoveAt(index - startIndex);
}
public void Add(T item)
{
inner.Add(item);
}
public void Clear()
{
inner.Clear();
}
public bool Contains(T item)
{
return inner.Contains(item);
}
public void CopyTo(T[] array, int arrayIndex)
{
inner.CopyTo(array, arrayIndex);
}
public int Count
{
get { return inner.Count; }
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove(T item)
{
return inner.Remove(item);
}
}
要使用它,需要初始化它,就像初始化普通的List<T>
一样,但是要指定起始索引(例如NonZeroList<int> myList = new NonZeroList<int>(20) { 0, 1, 2, 3 };
)。然后,您可以像使用普通List<T>
或T[]
一样使用它。
如果您想将其用作数组而不是列表,那么您可以简单地添加边界检查或实现IEnumerable<T>
而不是IList<T>
,并自己创建实用程序函数。