数组未必一定需从0开始,谈一下非0开始的数组

  谈到数组时,当被问及数组是从什么数开始时,估计大部分程序员都会直接说出数组当然是从0开始的。这个回答当然没有错,现在我们就来了解一下C#中的下限非0的数组。

  首先看一下数组的相关介绍:

      1.数组:是允许将多个数据项当作一个集合来处理的机制。

      2.数组的分类:在CLR中,数组可分为一维数组,多维数组,交错数组。

      3.数组的类型:由于所有的数组都是继承自System.Array这个抽象类型,而这个类型又是继承自System.Object,这就说明数组是引用类型。

  在创建数组时,除了有数组元素,数组对象占据的内存块还包含一个类型对象指针,一个同步索引块和一个额外的成员。上面对数组的分类中提到“交错数组”,由于CLR支持交错数组,所以在C#中可以实现交错数组,交错数组即由数组构成的数组,在访问交错数组的元素意味着必须进行两次或多次数组访问。

  在对数组进行相关操作的过程中,数组作为实参传给一个方法时,实际传递的是对该数组的引用,因此被调用的方法能够修改数组中的元素。(如果不想被修改,必须生成数组的一个拷贝,并将这个拷贝传给方法。)

  下面介绍一种将数组转化为DataTable的方法:

        /// <summary>
        /// 整数型二维数组转换成DataTable
        /// </summary>
        /// <param name="intDyadicArray"></param>
        /// <param name="messageOut"></param>
        /// <param name="dataTableColumnsName"></param>
        /// <returns></returns>
        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<Array>() != null);
            Contract.Ensures(Contract.Result<Array>().Length == length); 
            Contract.Ensures(Contract.Result<Array>().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"); 
        }
static partial void AssertMustUseRewriter(ContractFailureKind kind, String contractKind); 
        [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;
        } 

     有关非零基数组的创建方法就不做深入的介绍,如果需要使用,可以根据提供的方法重载选择对应的版本实现。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏上善若水

006-golang中XML文件的处理

data),那么,字符数据会被累加到struct中第一个有tag为”,chardata”的字段。struct字段的类型可以是string或[]byte。如果没有...

872
来自专栏程序员互动联盟

【编程基础】Java里面如何对字符串排序?

前几天有同学在群里问一个Java面试题,上面的思路很正确大概分为几步: 1、分割字符串: 用到的方法是String类的 public String[] spl...

3899
来自专栏大数据钻研

js中call、apply、bind那些事

前言 回想起之前的一些面试,几乎每次都会问到一个js中关于call、apply、bind的问题,比如… 怎么利用call、apply来求一个数组中最大或者最小值...

2605
来自专栏技术专栏

Scala入门与进阶(五)- 模式匹配

661
来自专栏大数据钻研

JavaScript arguments 对象详解

1. 什么是 arguments MDN 上解释: arguments 是一个类数组对象。代表传给一个function的参数列表。 我们先用一个例子直观了解下 ...

41410
来自专栏书山有路勤为径

C++ Vs Pythoninclude<iostream>

ython自动计算出vehicle_doors是一个整数,vehicle_speed是一个浮点数,vehicle_on是一个布尔变量。变量赋值是动态的。在Pyt...

654
来自专栏机器学习入门

挑战程序竞赛系列(95):3.6数值积分(1)

挑战程序竞赛系列(95):3.6数值积分(1) 传送门:AOJ 1313: Intersection of Two Prisms 题意: 有一个侧棱与Z轴平行...

19210
来自专栏python学习之旅

Python笔记(二):列表+列表数据处理+函数

#才疏学浅,难免有不恰当之处,请不吝指正,谢谢。 #适合初学者。     列表的数据自下而上堆放(形成一个堆栈),类似于其他编程语言的数组。例如: user =...

2825
来自专栏开发与安全

从零开始学C++之STL(九):函数适配器bind2nd 、mem_fun_ref 源码分析、函数适配器应用举例

一、适配器 三种类型的适配器: 容器适配器:用来扩展7种基本容器,利用基本容器扩展形成了栈、队列和优先级队列 迭代器适配器:(反向迭代器、插入迭代器、IO流迭代...

1910
来自专栏闪电gogogo的专栏

【数据结构(C语言版)系列三】 队列

队列是一种先进先出的线性表,它只允许在表的一端进行插入,而在另一端删除元素。这和我们日常生活中的排队是一致的,最早进入队列的元素最早离开。在队列中,允许插入的一...

1342

扫码关注云+社区