關(guān)于C#轉(zhuǎn)換二進制所引起的一些思考
前言
最近遇到很有意思轉(zhuǎn)換二進制的問題,有部分童鞋儼然已了解,可能也有一部分童鞋沒碰到過也就不知情,這里我們來深入學(xué)習(xí)下轉(zhuǎn)換二進制所帶來的問題。
二進制轉(zhuǎn)換問題
假設(shè)現(xiàn)在我們有一個int類型的數(shù)據(jù),它的范圍區(qū)間暫且定在0-15之間,我們需要將其轉(zhuǎn)換為二進制,然后獲取二進制中的每一位,若不足4位則0填充??此坪芎唵问遣皇?,直接通過C#內(nèi)置APi即可達到此需求,如下:
var binary = Convert.ToString(7, 2).PadLeft(4, '0').ToArray();
上述將數(shù)字7轉(zhuǎn)換為包含二進制位的字符串?dāng)?shù)組形式,7轉(zhuǎn)換二進制然后不足4位以0填充即(0111),我們?nèi)缦芦@取二進制位字符串?dāng)?shù)組為索引的位,結(jié)果應(yīng)該打印出0,對嗎?
var zerobit = binary[0]; Console.WriteLine(zerobit);

好像一點毛病也沒有,這是在控制臺中進行打印,若是將該數(shù)據(jù)導(dǎo)出到Excel中,你會發(fā)現(xiàn)結(jié)果將可能是48或49而不是0或1(你可以一試)這是因為如下:

我們通過調(diào)試可知實際上在字符0上還攜帶有48,這個48實際上是字符0的ASCII碼,字符1的ASCII碼是49,通過如下代碼即可證明:
foreach (var b in System.Text.Encoding.UTF8.GetBytes(binary))
{
Console.WriteLine(b.ToString());
}


我們對將對應(yīng)字符數(shù)組索引數(shù)據(jù)進行如下ToString轉(zhuǎn)換即可避免導(dǎo)出數(shù)據(jù)時可能出現(xiàn)的問題
var zerobit = binary[0]; Console.WriteLine(zerobit.ToString());
轉(zhuǎn)換字符數(shù)組問題
當(dāng)我們轉(zhuǎn)換為字符數(shù)組時,有兩種方式,既可采用上述ToArray方法,也可以通過ToCharArray方法來實現(xiàn),如下,那么哪種方法會更好呢?
var binary = Convert.ToString(7, 2).PadLeft(4, '0').ToArray(); var binary1 = Convert.ToString(7, 2).PadLeft(4, '0').ToCharArray();
此時比較此二者方法的性能好壞,只能去看對應(yīng)源碼實現(xiàn),首先我們來看看ToCharArray方法,如下:
public unsafe char[] ToCharArray()
{
if (Length == 0)
{
return Array.Empty<char>();
}
char[] array = new char[Length];
fixed (char* smem = &_firstChar)
{
fixed (char* dmem = &array[0])
{
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 * 2));
}
上述對于ToCharArray代碼量還是不多,我們來看看ToArray方法實現(xiàn),如下:
public static TSource[] ToArray<TSource>(this IEnumerable<TSource> source)
{
if (source == null)
{
throw Error.ArgumentNull("source");
}
return new Buffer<TSource>(source).ToArray();
}
上述只是寫了一個擴展方法,我們繼續(xù)往下看Buffer類的具體實現(xiàn),如下:
internal Buffer(IEnumerable<TElement> source)
{
TElement[] array = null;
int num = 0;
ICollection<TElement> collection = source as ICollection<TElement>;
if (collection != null)
{
num = collection.Count;
if (num > 0)
{
array = new TElement[num];
collection.CopyTo(array, 0);
}
}
else
{
foreach (TElement item in source)
{
if (array == null)
{
array = new TElement[4];
}
else if (array.Length == num)
{
TElement[] array2 = new TElement[checked(num * 2)];
Array.Copy(array, 0, array2, 0, num);
array = array2;
}
array[num] = item;
num++;
}
}
items = array;
count = num;
}
從代碼量上看就覺得ToArray方法實現(xiàn)稍微復(fù)雜一點,所以我們選擇使用ToCharArray會更好,我要是如此草草結(jié)束此文,一定會噴。原歸正傳,我們一步步來分析,如上做了一點優(yōu)化,首先會判斷參數(shù)是否屬于集合接口,若是則直接通過復(fù)制轉(zhuǎn)換為數(shù)組形式,但是我們知道字符串肯定沒有實現(xiàn)ICollection<T>接口,所以走另外一個條件分支,但是有的童鞋可能就有疑問了,此時為何可以遍歷呢?那是因為針對字符實現(xiàn)了IEnumerable<char>接口,所以可以進行遍歷,如下:
public sealed class CharEnumerator : IEnumerator, ICloneable, IEnumerator<char>, IDisposable
{......}
接下來則是初始化容量為4的數(shù)組,為何這里為4呢?這里我認為應(yīng)該談不上優(yōu)化,與其說是實現(xiàn)者的一種拍腦袋的想法,我傾向于理解為是一種權(quán)衡或考量,既然轉(zhuǎn)到此分支說明一定是轉(zhuǎn)換為二進制位的數(shù)組,比如上述進行填充后長度剛好為4。再接下來無用我再多講,就是遍歷所有字符數(shù)組,將每一個字符串添加到數(shù)組中去,直到數(shù)組長度和變量值(num)相等最終進行一次性復(fù)制,最終將數(shù)組賦值給數(shù)組元素以及將變量num賦值給數(shù)組元素的數(shù)量(count)。
好了,講解了這么多,那么問題來了,到底誰的性能會更好呢?ToCharArray方法實現(xiàn)底層采用指針操作轉(zhuǎn)化為字符數(shù)組,而利用ToArray方法由于string沒有實現(xiàn)ICollection<T>接口,也就是說根本不清楚字符串中字符數(shù)組的長度,所以只能采取低效遍歷的方式去進行轉(zhuǎn)換,我們可認為通過中間緩沖區(qū)的方式(即上述通過實例化數(shù)組作為橋梁最終進行復(fù)制)實現(xiàn)。由此得出,在將字符串轉(zhuǎn)換為字符數(shù)組時,一定要用ToCharArray方法而不是ToArray,ToCharArray性能優(yōu)于ToArray方法,我不禁在想,針對字符轉(zhuǎn)換為數(shù)組只提供ToCharArray方法不就好了么,為何還要提供ToArray方法,讓人容易產(chǎn)生誤會,它的場景難道還有其他嗎?
總結(jié)
本文詳細講解了在轉(zhuǎn)換二進制數(shù)據(jù)所引發(fā)的一點個人思考,在將字符串轉(zhuǎn)換為字符數(shù)組時,通過方法名稱意思可能直接就用ToCharArray方法,但是又偏偏提供了字符串的ToArray方法,其本質(zhì)是針對字符數(shù)組的擴展方法,如果對源碼不了解的話,根本就不清楚到底應(yīng)該用哪一個,從性能角度講,ToCharArray方法優(yōu)于ToArray方法,至于最終用哪一個,你說了算。
到此這篇關(guān)于關(guān)于C#轉(zhuǎn)換二進制所引起的文章就介紹到這了,更多相關(guān)C#轉(zhuǎn)換二進制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
淺析c#范型中的特殊關(guān)鍵字where & default
以下是對c#范型中的特殊關(guān)鍵字where和default進行了詳細的介紹,需要的朋友可以過來參考下2013-09-09
C#學(xué)習(xí)基礎(chǔ)概念二十五問續(xù)2
C#學(xué)習(xí)基礎(chǔ)概念二十五問續(xù)2...2007-04-04
C#編程實現(xiàn)連接SQL SERVER數(shù)據(jù)庫實例詳解
這篇文章主要介紹了C#編程實現(xiàn)連接SQL SERVER數(shù)據(jù)庫的方法,以實例形式較為詳細的分析了C#連接SQL SERVER數(shù)據(jù)庫的相關(guān)步驟與具體實現(xiàn)技巧,需要的朋友可以參考下2015-11-11

