谈到数组时,当被问及数组是从什么数开始时,估计大部分程序员都会直接说出数组当然是从0开始的。这个回答当然没有错,现在我们就来了解一下c#中的下限非0的数组。
首先看一下数组的相关介绍:
1.数组:是允许将多个数据项当作一个集合来处理的机制。
2.数组的分类:在clr中,数组可分为一维数组,多维数组,交错数组。
3.数组的类型:由于所有的数组都是继承自system.array这个抽象类型,而这个类型又是继承自system.object,这就说明数组是引用类型。
在创建数组时,除了有数组元素,数组对象占据的内存块还包含一个类型对象指针,一个同步索引块和一个额外的成员。上面对数组的分类中提到“交错数组”,由于clr支持交错数组,所以在c#中可以实现交错数组,交错数组即由数组构成的数组,在访问交错数组的元素意味着必须进行两次或多次数组访问。
在对数组进行相关操作的过程中,数组作为实参传给一个方法时,实际传递的是对该数组的引用,因此被调用的方法能够修改数组中的元素。(如果不想被修改,必须生成数组的一个拷贝,并将这个拷贝传给方法。)
下面介绍一种将数组转化为datatable的方法:
///
/// 整数型二维数组转换成datatable
///
///
///
///
///
public datatable dyadicarraytodatatable(int[,] intdyadicarray, out string messageout,
params object[] datatablecolumnsname)
{
var returndatatable = new datatable();
//验证列与所传入的字符是否相符
if (datatablecolumnsname.length != intdyadicarray.getlength(1))
{
messageout = datatable列数与二维数组列数不符,请调整列数;
return returndatatable;
}
//添加列
for (var datatablecolumnscount = 0;
datatablecolumnscount < datatablecolumnsname.length;
datatablecolumnscount++)
{
returndatatable.columns.add(datatablecolumnsname[datatablecolumnscount].tostring());
}
//添加行
for (var dyadicarrayrow = 0; dyadicarrayrow < intdyadicarray.getlength(0); dyadicarrayrow++)
{
var adddatarow = returndatatable.newrow();
for (var dyadicarraycolumns = 0;
dyadicarraycolumns < intdyadicarray.getlength(1);
dyadicarraycolumns++)
{
adddatarow[datatablecolumnsname[dyadicarraycolumns].tostring()] =
intdyadicarray[dyadicarrayrow, dyadicarraycolumns];
}
returndatatable.rows.add(adddatarow);
}
//返回提示与datatable
messageout = datatable成功转换;
return returndatatable;
}
以上是将整数数组转化为datatable的操作方法,至于其他类型,如字节,浮点型等类型的转化,修改相关参数即可,也可将参数类型进行对应的修改,这里就不做详细介绍了。
接下来我们具体来了解一下“下限非零数组”的相关知识:
下限非零数组由于在性能上没有做更好的优化,因此在一般的使用中会较少,如果不计较性能损失或者需要跨语言移植,可以考虑使用非零数组。“下限非零数组”的概念就不做介绍,正如其名称所见。
c#中使用array的createinstance()方法进行创建,此方法有若干个重载,允许指定数组元素类型,数组维数,每一维的下限和每一维的元素数目。
在调用createinstance()时,为数组分配内存,将参数信息保存到数组的内存的开销部分,然后返回对数组的一个引用。
接下来看一下此方法的底层实现代码:
[system.security.securitysafecritical] // auto-generated
public unsafe static array createinstance(type elementtype, int length)
{
if ((object)elementtype == null)
throw new argumentnullexception(elementtype);
if (length < 0)
throw new argumentoutofrangeexception(length, environment.getresourcestring(argumentoutofrange_neednonnegnum));
contract.ensures(contract.result() != null);
contract.ensures(contract.result().length == length);
contract.ensures(contract.result().rank == 1);
contract.endcontractblock();
runtimetype t = elementtype.underlyingsystemtype as runtimetype;
if (t == null)
throw new argumentexception(environment.getresourcestring(arg_mustbetype),elementtype);
return internalcreate((void*)t.typehandle.value,1,&length,null);
}
看到以上的代码,应该对非零基数组的创建有一个大致了解,接下来具体看一下ensures()方法的底层代码:
public static void ensures(bool condition)
{
assertmustuserewriter(contractfailurekind.postcondition, ensures);
}
[securitysafecritical]
static partial void assertmustuserewriter(contractfailurekind kind, string contractkind)
{
if (_assertingmustuserewriter)
system.diagnostics.assert.fail(asserting that we must use the rewriter went reentrant., didn't rewrite this mscorlib?);
_assertingmustuserewriter = true;
assembly thisassembly = typeof(contract).assembly;
stacktrace stack = new stacktrace();
assembly probablynotrewritten = null;
for (int i = 0; i < stack.framecount; i++)
{
assembly caller = stack.getframe(i).getmethod().declaringtype.assembly;
if (caller != thisassembly)
{
probablynotrewritten = caller;
break;
}
}
if (probablynotrewritten == null)
probablynotrewritten = thisassembly;
string simplename = probablynotrewritten.getname().name;
system.runtime.compilerservices.contracthelper.triggerfailure(kind, environment.getresourcestring(mustuseccrewrite, contractkind, simplename), null, null, null);
_assertingmustuserewriter = false;
}
有关非零基数组的创建方法就不做深入的介绍,如果需要使用,可以根据提供的方法重载选择对应的版本实现。
