2012-05-13 31 views
13

Trong serialiser tôi/deserialiser, tôi có đoạn mã sau:Cách nhanh nhất để kiểm tra xem một loại có bị blittable không?

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 
     } 
    } 

Mục đích của nó là để thử và viết một loạt các loại giá trị cho một dòng suối, một cách hiệu quả nhất có thể (có nghĩa là, chỉ cần nội dung dưới dạng một loạt các byte).

Sự cố xảy ra khi loại là loại giá trị nhưng không thể xóa được và Alloc() không thành công. Tại thời điểm ngoại lệ bị bắt và kiểm soát được chuyển tới mã liên quan đến mảng như thể nó bao gồm các kiểu tham chiếu.

Tuy nhiên, kiểm tra này (do việc ném và bắt ngoại lệ mà tôi hiểu rất chậm) đang chứng minh là một nút cổ chai nghiêm trọng do số lượng loại giá trị gặp phải trong đơn đăng ký của tôi. Vì vậy, tôi tự hỏi, cách nhanh nhất để kiểm tra xem một loại là blittable là gì?

+0

Tôi gặp vấn đề tương tự, tôi đã kết thúc lưu vào bộ nhớ cache kết quả cho từng loại (ví dụ: trong từ điển tĩnh). Việc kiểm tra được thực hiện giống như ở đây, hãy thử/nắm bắt. –

Trả lời

4

Tôi đang sử dụng lớp tổng quát để kết quả bộ nhớ cache. Kiểm tra được thực hiện theo cùng một cách (cố gắng phân bổ xử lý được ghim).

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

Caching là những gì tôi đã kết thúc, mặc dù tôi nghĩ rằng kỹ thuật bộ nhớ đệm của bạn ở đây là hiệu quả nhất mà tôi đã thấy! – sebf

0

Sử dụng http://msdn.microsoft.com/en-us/library/system.type.islayoutsequential.aspxhttp://msdn.microsoft.com/en-us/library/system.type.isexplicitlayout.aspx:

element_type.IsValueType && collection_type.IsArray && (element_type.IsLayoutSequential || element_type.IsExplicitLayout) 
+2

Cảm ơn nhưng tiếc là điều này không hoạt động. Thuộc tính IsLayoutSequential là đúng cho ít nhất một kiểu không blittable mà tôi đã thử (một cấu trúc đơn giản với một chuỗi). – sebf

6

Câu trả lời hiện tại hoạt động đối với trường hợp của người hỏi nhưng, theo đặc điểm kỹ thuật, các loại giá trị có thể blittable cũng là các loại blittable. Mở rộng phương pháp Ondřej của một chút, vì vậy phải mất này vào tài khoản, và cũng làm việc với nhiều loại tài liệu tham khảo:

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)); 
} 

Như một tác dụng phụ, lợi nhuận này (mặc dù đúng) false cho string, vì GetUninitializedObject không thể tạo ra nó. Giả sử Alloc thực sự kiểm tra tính dễ bị tổn thương (ngoại trừ string), điều này đáng tin cậy.

+0

Điều này sẽ trả về 'false' với' int [] ', tuy nhiên nó có thể bị xóa. Xóa NOT khỏi '! Elem.IsValueType' để sửa :) – FooBarTheLittle

+0

@FooBarTheLittle Cảm ơn bạn! – IllidanS4

+0

Bạn được chào đón. – FooBarTheLittle

2

Mã tuyệt vời của @ IllidanS4 trên trang này trả về không chính xác false cho các mảng trong đó phần tử là một blittable formatted type, có nghĩa là mảng đó cũng có thể blittable. Bắt đầu từ ví dụ đó, tôi cố định vấn đề đó và thêm vào xử lý trong một vài trường hợp xử lý sai hơn, chẳng hạn như:

  • T[] nơi T: định dạng kiểu (chỉ đề cập)
  • mảng lởm chởm int[][][]...
  • enums (nhưng không phải System.Enum ittself)
  • giao diện, loại trừu tượng
  • loại chung (không bao giờ bị vỡ).

Tôi cũng đã thêm trường hợp để tránh tốn kém Exception chặn thử nghiệm đơn vị đầy đủ hơn và chạy đơn vị cho tất cả các loại khác nhau của các loại mà tôi có thể nghĩ đến.

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; 
} 

Cơ chế lưu bộ nhớ đệm tốt nhất từ ​​câu trả lời khác phải được sử dụng như nguyên trạng.

+0

Ý tưởng hay để kiểm tra các loại khác. Chỉ có một sai lầm nhỏ, 'bool' và' char', trong khi nguyên thủy, không blittable (kích thước phụ thuộc vào nền tảng). Ngoài ra các mảng răng cưa không nên blittable, vì chúng là mảng tham chiếu đối tượng. Không phải là mảng đa chiều, mỗi [MSDN] (https://msdn.microsoft.com/en-us/library/75dwhxf7%28v=vs.110%29.aspx), mặc dù mã của tôi có cùng một vấn đề. – IllidanS4

Các vấn đề liên quan