1. 程式人生 > 程式設計 >關於C#轉換二進位制所引起的一些思考

關於C#轉換二進位制所引起的一些思考

前言

最近遇到很有意思轉換二進位制的問題,有部分童鞋儼然已瞭解,可能也有一部分童鞋沒碰到過也就不知情,這裡我們來深入學習下轉換二進位制所帶來的問題。

二進位制轉換問題

假設現在我們有一個int型別的資料,它的範圍區間暫且定在0-15之間,我們需要將其轉換為二進位制,然後獲取二進位制中的每一位,若不足4位則0填充。看似很簡單是不是,直接通過C#內建APi即可達到此需求,如下:

var binary = Convert.ToString(7,2).PadLeft(4,'0').ToArray();

上述將數字7轉換為包含二進位制位的字串陣列形式,7轉換二進位制然後不足4位以0填充即(0111),我們如下獲取二進位制位字串陣列為索引的位,結果應該打印出0,對嗎?

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

關於C#轉換二進位制所引起的一些思考

好像一點毛病也沒有,這是在控制檯中進行列印,若是將該資料匯出到Excel中,你會發現結果將可能是48或49而不是0或1(你可以一試)這是因為如下:

關於C#轉換二進位制所引起的一些思考

我們通過除錯可知實際上在字元0上還攜帶有48,這個48實際上是字元0的ASCII碼,字元1的ASCII碼是49,通過如下程式碼即可證明:

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

關於C#轉換二進位制所引起的一些思考

關於C#轉換二進位制所引起的一些思考

我們對將對應字元陣列索引資料進行如下ToString轉換即可避免匯出資料時可能出現的問題

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

轉換字元陣列問題

當我們轉換為字元陣列時,有兩種方式,既可採用上述ToArray方法,也可以通過ToCharArray方法來實現,如下,那麼哪種方法會更好呢?

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

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

此時比較此二者方法的效能好壞,只能去看對應原始碼實現,首先我們來看看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方法實現,如下:

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 = 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,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#轉換二進位制所引起的文章就介紹到這了,更多相關C#轉換二進位制內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!