byte[]、sbyte[]、int[]以及Array的故事

很久没有搞比较底层一点的东西了,最近又开始搞,于是乎又发现了一些很鸡毛蒜皮的事情。也许有人已经发现过了,那就请原谅我就再来挖掘一遍。

byte[]、sbyte[]、int[]等数组,是一种特殊的类型,他们都继承自Array。不过这个继承还不是一般的继承关系,编译器和CLI都做了一些特殊的工作。我们先看普通的继承关系:

class Human
{
}

class Man : Human
{
}

class Woman : Human
{
}

如果我们试图写下列的代码:

Human human = new Man();
Woman woman = (Woman)human;

那么结果是什么,你懂的。

好吧,你不懂。那我给说一下,Man和Woman都是从Human这个类继承的,因此Man和Woman是兄妹关系,兄妹之间实际上是不能互相转换的。虽然上面的代码是可以编译通过的,但是运行起来就会抛异常,告诉你Man类型的对象是不能转换成Woman的。

不过换到byte[]、sbyte[]等数组里面,就不是这么简单了。比如说:

byte[] source = {1, 2, 3};
sbyte[] target = (sbyte[])(Array)source;
foreach(var item in target)
{
    Console.WriteLine(item);
}

你猜怎么着?哎?为啥居然能跑呢?按道理byte[]和sbyte[]都是从Array派生的,那么他们之间自然也是兄妹关系了。看来CLI为我们做了一些事情。好了,那么当我们有这么一个函数:

static public void Copy(sbyte[] source, sbyte[] target)
{
    if (source == null)
    {
        throw new ArgumentNullException("source");
    }
    if (target == null)
    {
        throw new ArgumentNullException("target");
    }
    int copyLength = Math.Min(source.Length, target.Length);
    Array.Copy(source, target, copyLength);
}

然后这么调用:

sbyte[] target = GetTarget();
sbyte[] another = new sbyte[3];
Copy(target, another);

在Copy函数内会出现除了ArgumentNullException之外的其它异常吗?这个怎么看也是不能吧?错了,可能会出现InvalidCastException异常,假如GetTarget的代码是:

sbyte[] GetTarget()
{
    return (sbyte[])(Array)new byte[] {1, 2, 3};
}

这就奇怪了,为啥咧?因为Array.Copy会判断要复制的数组,其元素类型之间是什么关系。这个还不是简单的相等关系,说这个之前,我们再看另一个古怪的例子:

byte[] source = { 1, 2, 3 };
int[] intArray = (int[])(Array)source;

这个照样还是能够编译的,不过运行时会抛出来InvalidCastException。飞鸽传书:http://www.freeeim.com/,为什么sbyte[]和byte[]之间可以互相转换,同样是兄妹关系的byte[]和int[]就不能互相转换呢?其实,这个问题不需要深究都会知道,sbyte和byte[]的元素所占字节数都一样,所以理论上是可以直接转换来访问的。而int[]和byte[]之间,如果因为其元素一个是4字节另一个是1字节,而导致不允许直接进行转换,那也很正常。不过,既然sbyte[]和byte[]之间都可以强制转换,而且转换之后都可以访问元素,为啥就不能通过Array.Copy来复制呢?嗯,不用想,Array.Copy对于源数组和目标数组的元素类型进行了判断,至于咋判断的Reflector看不到,我们就先猜测吧:Array.Copy只要发现源和目标数组的元素类型不一样,那就不能够复制。真是这样吗?我们再看另一个例子:

byte[] source = {1, 2, 3};
int[] intArray = new int[source.Length];
Array.Copy(source, intArray, source.Length);
foreach(var item in intArray)
{
    Console.WriteLine(item);
}

怎么样,这个代码你觉得跑起来会如何?抛InvalidCastException?ArrayTypeMismatchException?其实什么都不会抛出来。原来,Array.Copy检验的条件是,如果源和目标数组的元素类型是内置的值类型,只要能做宽转换(widening conversion)那就可以成功复制。比如byte->int,反之就会抛异常。而用户自定义的值类型就没有这个优惠政策了,哪怕你重写了类型转换操作符,或者实现了IConvertible,都不行。当然了,实际上Array.Copy的判断比这里写的复杂,具体还是参考MSDN吧。

byte[]、sbyte[]之间的强制转换和Array.Copy的问题,如果分别独立的看,可能没有什么问题。但如果我们合起来看,就会出现一些意想不到的状况。比如说,你写了一个函数:

代码
        /*
         * 将第index位的元素修改为value值,然后将整个数组的元素复制一遍。
         * 比如原来是{1,2,3},调用SomeBusiness(source, 8, 1)完成后就变成
         * {1,8,3,1,8,3}
         */
        static public sbyte[] SomeBusiness(sbyte[] source, sbyte value, int index)
        {
            source[index] = value; // 你看,这个地方可以用的,所以下面一句看起来也应该可以。
            return (sbyte[])(Array)Duplicate((byte[])(Array)source);
        }

static public byte[] Duplicate(byte[] source)
        {
            var result = source.ToList(); // 竟然出现ArrayTypeMismatchException?百思不得其解。
            result.AddRange(result);
            return result.ToArray();
        }

尤其是SomeBusiness和Duplicate不是同一个人开发的时候。

byte[]、sbyte[]、int[]以及Array的故事相关推荐

  1. C# int uint long ulong byte sbyte float double decimal 范围,及类型!

    C# int uint long ulong byte sbyte float double decimal 范围,及类型! static void Main(string[] args){Conso ...

  2. c# 数据byte转换int

    今天在做上位机与PLC通信时,对方是协议将数据按照int16发给上位机,但是上位机接收到的数据是高八位在前,低八位在后.而Csharp 中BitConverter.toUint16默认转换时,数据是低 ...

  3. java write_java中write(byte[] b)与write(byte[] b,int off,int len)区别

    在项目中要上传文件或者图片 private static final int BUFFER_SIZE = 16 * 1024; private static void copy(File src, F ...

  4. 基于java的InputStream.read(byte[] b,int off,int len)算法学习!

    public int read(byte[] b,int off,int len)throws IOException 将输入流中最多 len 个数据字节读入字节数组.尝试读取多达 len 字节,但可 ...

  5. C++: byte和int的相互转化

    byte不是一种新类型,在C++中byte被定义的是unsigned char类型:但在C#里面byte被定义的是unsigned int类型 //int转byte void  intToByte(i ...

  6. byte转换int时为何与0xff进行与运算

    2019独角兽企业重金招聘Python工程师标准>>> ava中byte转换int时为何与0xff进行与运算 在剖析该问题前请看如下代码 public static String b ...

  7. java write int,void write(byte[] b, int off, int len)

    void write(byte[] b, int off, int len) 描述 (Description) java.io.PipedOutputStream.write(byte[] b, in ...

  8. String(byte[] bytes, int offset, int length)

    public String(byte[] bytes, int offset, int length) 通过使用平台的默认字符集解码指定的 byte 子数组,构造一个新的 String. 参数: by ...

  9. pythonint函数的参数_向嵌入的Python函数传递两个参数(int和array)

    我需要从我的模块中调用Python函数并为其设置两个参数:int和array.在 现在我在调用这个函数的时候遇到了segfault,我不知道我做错了什么.有人能指出我的错误在哪里吗?在 函数在我的Py ...

最新文章

  1. mysql事务拼写_拼写mysql单词
  2. [深入浅出Cocoa]详解键值观察(KVO)及其实现机理
  3. nginx 官方手册 php,nginx + php 的配置
  4. 倾斜模型精细化处理_推荐一款好用的倾斜摄影精细化单体建模软件——OSketch...
  5. 以太坊 node data write error_Node之 创建服务器与客户端
  6. linux mysql 修改root密码_Mac下重置mysql的root密码
  7. “Spring入门”教程系列
  8. python3 面向对象编程 下载_Python3(7) Python 面向对象编程
  9. 子组件调用父组件方法
  10. DEDECMS使用SQL语句批量删除文章
  11. 走近夜间灯光——教你平均灯光指数(ANLI)如何得到(超详细)
  12. c语言图灵机算法,图灵机的时间化简概述(3/4)
  13. fragstats移动窗口
  14. 万字干货,Podman 保姆级中文使用教程
  15. Math函数生成随机数用法
  16. 【网络】PFC背景和原理 (DCB=PFC + ETS)
  17. Python 使用SMTP协议发送邮件
  18. ZigBee学习笔记——(三)ZigBee无线传感器网络通信标准
  19. Linux设置防火墙
  20. 全国高等学校计算机等级考试大纲,全国高等学校计算机等级考试大纲.doc

热门文章

  1. 笔记本上的小键盘计算机怎样用,笔记本数字小键盘不能用怎么办【解决方法】...
  2. 启动kafka失败报内存不足(Cannot allocate memory)
  3. 面试题,你什么时候可以入职?回答不好,容易被压薪资
  4. 2020中国男士美妆市场洞察报告
  5. java图片失真_java 图片合成 解决图片失真问题
  6. 【UI/UX】桌面GUI设计
  7. 【数据结构与算法】带权图最短路径Dijkstra算法
  8. 【VB.NET】基于Visual Studio编写VB.NET程序的常见问题的解答
  9. Linux RAID磁盘阵列
  10. Python suds error “'NoneType' object has no attribute 'promotePrefixes'”