前言

最近遇到很有意思转换二进制的问题,有部分童鞋俨然已了解,可能也有一部分童鞋没碰到过也就不知情,这里我们来深入学习下转换二进制所带来的问题。

二进制转换问题

假设现在我们有一个int类型的数据,它的范围区间暂且定在0-15之间,我们需要将其转换为二进制,然后获取二进制中的每一位,若不足4位则0填充。看似很简单是不是,直接通过C#内置APi即可达到此需求,如下:

 var binary = Convert.ToString(, ).PadLeft(, '').ToArray();

上述将数字7转换为包含二进制位的字符串数组形式,7转换二进制然后不足4位以0填充即(0111),我们如下获取二进制位字符串数组为索引的位,结果应该打印出0,对吗?

var zerobit = binary[];
Console.WriteLine(zerobit);

好像一点毛病也没有,这是在控制台中进行打印,若是将该数据导出到Excel中,你会发现结果将可能是48或49而不是0或1(你可以一试)这是因为如下:

我们通过调试可知实际上在字符0上还携带有48,这个48实际上是字符0的ASCII码,字符1的ASCII码是49,通过如下代码即可证明:

foreach (var b in System.Text.Encoding.UTF8.GetBytes(binary))
{
Console.WriteLine(b.ToString());
}

我们对将对应字符数组索引数据进行如下ToString转换即可避免导出数据时可能出现的问题

var zerobit = binary[];
Console.WriteLine(zerobit.ToString());

转换字符数组问题

当我们转换为字符数组时,有两种方式,既可采用上述ToArray方法,也可以通过ToCharArray方法来实现,如下,那么哪种方法会更好呢?

var binary = Convert.ToString(, ).PadLeft(, '').ToArray();

var binary1 = Convert.ToString(, ).PadLeft(, '').ToCharArray();

此时比较此二者方法的性能好坏,只能去看对应源码实现,首先我们来看看ToCharArray方法,如下:

public unsafe char[] ToCharArray()
{
if (Length == )
{
return Array.Empty<char>();
}
char[] array = new char[Length];
fixed (char* smem = &_firstChar)
{
fixed (char* dmem = &array[])
{
wstrcpy(dmem, smem, Length);
}
}
return array;
}
internal unsafe static void wstrcpy(char* dmem, char* smem, int charCount)
{
Buffer.Memmove((byte*)dmem, (byte*)smem, (uint)(charCount * ));
}

上述对于ToCharArray代码量还是不多,我们来看看ToArray方法实现,如下:

public static TSource[] ToArray<TSource>(this IEnumerable<TSource> source)
{
if (source == null)
{
throw Error.ArgumentNull("source");
}
return new Buffer<TSource>(source).ToArray();
}

上述只是写了一个扩展方法,我们继续往下看Buffer类的具体实现,如下:

internal Buffer(IEnumerable<TElement> source)
{
TElement[] array = null;
int num = ;
ICollection<TElement> collection = source as ICollection<TElement>;
if (collection != null)
{
num = collection.Count;
if (num > )
{
array = new TElement[num];
collection.CopyTo(array, );
}
}
else
{
foreach (TElement item in source)
{
if (array == null)
{
array = new TElement[];
}
else if (array.Length == num)
{
TElement[] array2 = new TElement[checked(num * )];
Array.Copy(array, , array2, , num);
array = array2;
}
array[num] = item;
num++;
}
}
items = array;
count = num;
}

从代码量上看就觉得ToArray方法实现稍微复杂一点,所以我们选择使用ToCharArray会更好,我要是如此草草结束此文,一定会喷。原归正传,我们一步步来分析,如上做了一点优化,首先会判断参数是否属于集合接口,若是则直接通过复制转换为数组形式,但是我们知道字符串肯定没有实现ICollection<T>接口,所以走另外一个条件分支,但是有的童鞋可能就有疑问了,此时为何可以遍历呢?那是因为针对字符实现了IEnumerable<char>接口,所以可以进行遍历,如下:

public sealed class CharEnumerator : IEnumerator, ICloneable, IEnumerator<char>, IDisposable
{......}

接下来则是初始化容量为4的数组,为何这里为4呢?这里我认为应该谈不上优化,与其说是实现者的一种拍脑袋的想法,我倾向于理解为是一种权衡或考量,既然转到此分支说明一定是转换为二进制位的数组,比如上述进行填充后长度刚好为4。再接下来无用我再多讲,就是遍历所有字符数组,将每一个字符串添加到数组中去,直到数组长度和变量值(num)相等最终进行一次性复制,最终将数组赋值给数组元素以及将变量num赋值给数组元素的数量(count)。

好了,讲解了这么多,那么问题来了,到底谁的性能会更好呢?ToCharArray方法实现底层采用指针操作转化为字符数组,而利用ToArray方法由于string没有实现ICollection<T>接口,也就是说根本不清楚字符串中字符数组的长度,所以只能采取低效遍历的方式去进行转换,我们可认为通过中间缓冲区的方式(即上述通过实例化数组作为桥梁最终进行复制)实现。由此得出,在将字符串转换为字符数组时,一定要用ToCharArray方法而不是ToArray,ToCharArray性能优于ToArray方法,我不禁在想,针对字符转换为数组只提供ToCharArray方法不就好了么,为何还要提供ToArray方法,让人容易产生误会,它的场景难道还有其他吗?

总结

本文详细讲解了在转换二进制数据所引发的一点个人思考,在将字符串转换为字符数组时,通过方法名称意思可能直接就用ToCharArray方法,但是又偏偏提供了字符串的ToArray方法,其本质是针对字符数组的扩展方法,如果对源码不了解的话,根本就不清楚到底应该用哪一个,从性能角度讲,ToCharArray方法优于ToArray方法,至于最终用哪一个,你说了算。

C#由转换二进制所引起的思考,了解下?的更多相关文章

  1. Formiko总结整数十进制转换二进制原理

    引子: 为什么十进制转二进制的“辗转相除记录余数倒序输出”的算法是正确的?这个问题陪伴了Formiko半年. 实践: 实践一:把十进制数100转换成二进制数的图   上图和和下图唯一的区别在最后一位上 ...

  2. Python 进制转换 二进制 八进制 十进制 十六进制

    Python 进制转换 二进制 八进制 十进制 十六进制 作者:方倍工作室 地址:http://www.cnblogs.com/txw1958/p/python3-scale.html 全局定义一定不 ...

  3. Java 进制转换(二进制(负),八进制,十进制,十六进制),位运算、逻辑运算(2)

    负数的二进制表现形式:其实就是该数的绝对值取反+1. 进制转换(二进制,八进制,十进制,十六进制),原理解析 十六进制的表现形式: (2)(与.异或.左移.右移.三元运算符)

  4. python的进制转换二进制,八进制,十六进制及其原理

    #!usr/bin/env python# coding:utf-8def binary(): '''二进制的方法与算法'''    Number = 10    Number1 = 20    Nu ...

  5. IOS 图片转换二进制 二进制转换为图片

    //类方法 图片 转换为二进制 +(NSData *)Image_TransForm_Data:(UIImage *)image { NSData *imageData = UIImageJPEGRe ...

  6. C# 进制转换(二进制、十六进制、十进制互转)

    原文地址:https://www.cnblogs.com/icebutterfly/p/8884023.html C# 进制转换(二进制.十六进制.十进制互转)由于二进制数在C#中无法直接表示,所以所 ...

  7. 一次线上Redis类转换异常排查引发的思考

    之前同事反馈说线上遇到Redis反序列化异常问题,异常如下: XxxClass1 cannot be cast to XxxClass2 已知信息如下: 该异常不是必现的,偶尔才会出现: 出现该异常后 ...

  8. C# 进制转换(二进制、十六进制、十进制互转) 转载 https://www.cnblogs.com/icebutterfly/p/8884023.html

    C# 进制转换(二进制.十六进制.十进制互转)由于二进制数在C#中无法直接表示,所以所有二进制数都用一个字符串来表示例如: 二进制: 1010 表示为 字符串:"1010" int ...

  9. xxd命令转换二进制十六进制文件

    Linux下的xxd命令,可以把文件在二进制和十六进制之间互相转换. 1.准备需要转换的二进制文件 这个二进制文件可以是任意格式的, 示例中我们创建一个txt格式的二进制文件, vi demo.txt ...

随机推荐

  1. Java实现 蓝桥杯 历届试题 斐波那契

    试题 历届试题 斐波那契 资源限制 时间限制:1.0s 内存限制:256.0MB 问题描述 斐波那契数列大家都非常熟悉.它的定义是: f(x) = 1 - (x=1,2) f(x) = f(x-1) ...

  2. Java实现 蓝桥杯VIP 算法训练 友好数

    有两个整数,如果每个整数的约数和(除了它本身以外)等于对方,我们就称这对数是友好的.例如: 9的约数和有:1+3=4 4的约数和有:1+2=3 所以9和4不是友好的. 220的约数和有:1 2 4 5 ...

  3. Java实现 蓝桥杯VIP 算法训练 数位分离

    ** 算法训练 数位分离** 问题描述 编写一个程序,输入一个1000 以内的正整数,然后把这个整数的每一位数字都分离出来,并逐一地显示. 输入格式:输入只有一行,即一个1000以内的正整数. 输出格 ...

  4. Java实现ACMGoShopping

    ACMGoShopping Description 最近的YJ运气特别好,这不,他在路边摊买彩票,居然中了大奖.秉着见者有份的原则,他准备请咱们学校ACM训练基地的全体队员逛商场. 赶巧学校旁边有一家 ...

  5. Java实现 LeetCode 27 移除元素

    27. 移除元素 给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度. 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额 ...

  6. java实现第六届蓝桥杯格子中输出

    格子中输出 格子中输出 stringInGrid方法会在一个指定大小的格子中打印指定的字符串. 要求字符串在水平.垂直两个方向上都居中. 如果字符串太长,就截断. 如果不能恰好居中,可以稍稍偏左或者偏 ...

  7. keras搭建神经网络快速入门笔记

    之前学习了tensorflow2.0的小伙伴可能会遇到一些问题,就是在读论文中的代码和一些实战项目往往使用keras+tensorflow1.0搭建, 所以本次和大家一起分享keras如何搭建神经网络 ...

  8. Linux文件系统--基于EXT2

    一.文件系统基本知识 ① 存储在永久性存储介质,由程序按照某种格式制作的数据集合叫做文件 ② 磁盘上管理文件的文件.数据结构和操作构成磁盘文件系统,简称文件系统 ③ 文件属性 (1)名称 (2)位置 ...

  9. 03.Java的前世今生

    C&C++ 1972年C诞生 ◆贴近硬件,运行极快,效率极高. ◆操作系统,编译器,数据库,网络系统等 ◆指针和内存管理 1982年C++诞生 ◆面向对象 ◆兼容C ◆图形领域.游戏等 背景 ...

  10. boost常用库(一):boost数值转换

    在STL中有一些字符转换函数,例如atoi,itoa等,在boost里面只需用一个函数lexical_cast进行转换,lexical_cast是模板方法,使用时需要传入类型.只能是数值类型转字符串. ...