2012-05-13 41 views
13

在我的串行器/解串器,我有下面的代碼片段:最快的方法來檢查類型是blittable?

if (element_type.IsValueType && collection_type.IsArray) 
    { 
     try 
     { 
      GCHandle h = GCHandle.Alloc(array_object, GCHandleType.Pinned); 
      int arrayDataSize = Marshal.SizeOf(element_type) * c.Count; 
      var array_data = new byte[arrayDataSize]; 
      Marshal.Copy(h.AddrOfPinnedObject(), array_data, 0, arrayDataSize); 
      h.Free(); 
      WriteByteArray(array_data); 

      return; 
     } 
     catch (ArgumentException) 
     { 
      //if the value type is not blittable, then we need to serialise each array item one at a time 
     } 
    } 

,其目的是試圖寫值類型的流的陣列,以最有效的方式(即,只內容爲一串字節)。

問題出現在類型爲值類型但不是blittable且Alloc()失敗時。此時異常被捕獲並且控制傳遞給處理數組的代碼,就像它由引用類型組成一樣。

然而,由於在我的應用程序中遇到的值類型的數量,此檢查(由於拋出和捕獲我瞭解的異常非常緩慢)證明是嚴重的瓶頸。所以我想知道,什麼是檢查類型是blittable的最快方法?

+0

我有同樣的問題,我已經結束了每種類型的緩存結果(例如在靜態字典中)。檢查和這裏一樣,try/catch。 –

回答

4

我使用泛型類緩存結果。測試以相同的方式完成(試圖分配固定的句柄)。

public static class BlittableHelper<T> 
{ 
    public static readonly bool IsBlittable; 

    static BlittableHelper() 
    { 
     try 
     { 
      // Class test 
      if (default(T) != null) 
      { 
       // Non-blittable types cannot allocate pinned handle 
       GCHandle.Alloc(default(T), GCHandleType.Pinned).Free(); 
       IsBlittable = true; 
      } 
     } 
     catch { } 
    } 
} 
+0

緩存是我最終做的事情,儘管我認爲這裏的緩存技術是我見過的最高效的! – sebf

6

當前的答案適用於提問者的情況,但根據規範,blittable值類型的數組本身也是blittable類型。擴展的Ondrej的方法一點,所以考慮到了這,也適用於引用類型:

public static bool IsBlittable<T>() 
{ 
    return IsBlittableCache<T>.Value; 
} 

public static bool IsBlittable(Type type) 
{ 
    if(type.IsArray) 
    { 
     var elem = type.GetElementType(); 
     return elem.IsValueType && IsBlittable(elem); 
    } 
    try{ 
     object instance = FormatterServices.GetUninitializedObject(type); 
     GCHandle.Alloc(instance, GCHandleType.Pinned).Free(); 
     return true; 
    }catch{ 
     return false; 
    } 
} 

private static class IsBlittableCache<T> 
{ 
    public static readonly bool Value = IsBlittable(typeof(T)); 
} 

作爲一個副作用,此回報率(儘管是正確的)falsestring,因爲GetUninitializedObject不能創建它。假設Alloc真的檢查blittability(除了string),這應該是可靠的。

+0

這將會返回錯誤'int',但它仍然是blittable。刪除NOT!!elem.IsValueType'來修復:) – FooBarTheLittle

+0

@FooBarTheLittle謝謝! – IllidanS4

+0

不客氣。 – FooBarTheLittle

2

本頁上由@ IllidanS4編寫的優秀代碼錯誤地返回false,表示數組元素是blittable formatted type,這意味着該數組也是blittable。從該例子開始,我固定的問題,並添加處理對幾個把握不好的情況下,如:

  • T[]其中T:格式化型(剛纔提到)
  • 交錯數組int[][][]...
  • 枚舉(但不是System.Enum它自己)
  • 接口,抽象類型
  • 泛型類型(永不blittable)。

我還添加了專爲避免昂貴的Exception擋了一下更詳盡的情況下,跑單元測試的所有不同種類的,我能想到的類型。

public static bool IsBlittable(this Type T) 
{ 
    while (T.IsArray) 
     T = T.GetElementType(); 

    bool b; 
    if (!((b = T.IsPrimitive || T.IsEnum) || T.IsAbstract || T.IsAutoLayout || T.IsGenericType)) 
     try 
     { 
      GCHandle.Alloc(FormatterServices.GetUninitializedObject(T), GCHandleType.Pinned).Free(); 
      b = true; 
     } 
     catch { } 
    return b; 
} 

從其他答案的好緩存機制應該原樣使用。

+0

好主意檢查其他類型。只有一個小錯誤,'bool'和'char',而原始的,不是blittable(大小取決於平臺)。同樣鋸齒形的數組不應該是blittable,因爲它們是對象引用的數組。雖然我的代碼具有相同的問題,但每個[MSDN](https://msdn.microsoft.com/en-us/library/75dwhxf7%28v=vs.110%29.aspx)都不是多維數組。 – IllidanS4

相關問題