2013-04-15 36 views
7

Tôi đã dành nhiều giờ làm việc với mã không được quản lý và nền tảng gọi trong .NET. Đoạn mã dưới đây minh họa điều gì đó khiến tôi khó hiểu về cách dữ liệu không được quản lý được ánh xạ tới một đối tượng được quản lý trong .NET.Ánh xạ dữ liệu không được quản lý đến một cấu trúc được quản lý trong .NET

Ví dụ này tôi sẽ sử dụng RECT cấu trúc:

C++ RECT thực hiện (không được quản lý Win32 API)

typedef struct _RECT { 
    LONG left; 
    LONG top; 
    LONG right; 
    LONG bottom; 
} RECT, *PRECT; 

C thực hiện # RECT (quản lý .NET/C#)

[StructLayout(LayoutKind.Sequential)] 
public struct RECT 
{ 
    public int left, top, right, bottom; 
} 

Được rồi, vì vậy tương đương C# của tôi sẽ hoạt động, đúng? Ý tôi là, tất cả các biến đều theo thứ tự như cấu trúc C++, và nó sử dụng cùng tên biến.

Giả định của tôi là LayoutKind.Sequential có nghĩa là dữ liệu không được quản lý được ánh xạ tới đối tượng được quản lý theo cùng trình tự nó xuất hiện trong cấu trúc C++. tức là dữ liệu sẽ được lập bản đồ, bắt đầu bằng trái, sau đó trên cùng, sau đó sang phải, sau đó là dưới cùng.

Trên cơ sở này, tôi sẽ có thể sửa đổi cấu trúc C# của tôi ...

thực hiện C# RECT (một chút bụi)

[StructLayout(LayoutKind.Sequential)] 
public struct Rect //I've started by giving it a .NET compliant name 
{ 
    private int _left, _top, _right, _bottom; // variables are no longer directly accessible. 

    /* I can now access the coordinates via properties */ 
    public Int32 Left 
    { 
     get { return _left; } 
     set { this._left = value; } 
    } 

    public Int32 Top 
    { 
     get { return _top; } 
     set { this._top = value; } 
    } 

    public Int32 Right 
    { 
     get { return _right; } 
     set { this._right = value; } 
    } 

    public Int32 Bottom 
    { 
     get { return _bottom; } 
     set { this._bottom = value; } 
    } 
} 

Vậy điều gì sẽ xảy ra nếu các biến được khai báo trong sắp xếp sai? Có lẽ vít này lên các tọa độ bởi vì chúng sẽ không còn được ánh xạ tới đúng thứ gì nữa?

public struct RECT 
{ 
    public int top, right, bottom, left; 
} 

Tại một đoán, điều này sẽ lập bản đồ như vậy:

top = trái

đúng = top

đáy = đúng

trái = đáy ​​

Vì vậy, câu hỏi của tôi đơn giản là tôi có thể sửa đổi cấu trúc được quản lý theo điều kiện truy cập của mỗi biến, và thậm chí là tên biến, nhưng tôi không thể thay đổi thứ tự của các biến?

Trả lời

7

Nếu bạn thực sự muốn thay đổi thứ tự của các biến thành viên, bạn có thể thực hiện bằng cách sử dụng FieldOffsetAttribute. Chỉ làm cho nó ít hơn một chút có thể đọc được.

Bạn cũng sẽ cần phải đặt StructLayout thành LayoutKind.Explicit để cho biết bạn đang tự thiết lập bù trừ.

Ví dụ:

[StructLayout(LayoutKind.Explicit)] 
public struct RECT 
{ 
    [FieldOffset(4)] public int top; 
    [FieldOffset(8)] public int right; 
    [FieldOffset(12)] public int bottom; 
    [FieldOffset(0)] public int left; 
} 
+0

Câu trả lời hay. Ngắn gọn và dễ hiểu. +1 – series0ne

+0

Bạn thực sự thực sự thực sự không muốn làm điều này. –

2

Vâng, có vẻ như suy nghĩ của bạn là OK. StructLayout(LayoutKind.Sequential) là giá trị mặc định được áp dụng cho C# struct do đó bạn thậm chí không cần thực hiện việc này.Nhưng nếu bạn muốn có thứ tự các trường khác nhau, bạn có thể làm điều này bằng cách sử dụng StructLayout(LayoutKind.Explicite) và sau đó áp dụng thuộc tính FieldOffset cho mỗi trường - đây là cách tiếp cận tốt hơn nhiều vì bạn làm cho explicite những gì là implicite và không còn là bạn tùy thuộc vào một cái gì đó có thể easly được thay đổi như thứ tự định nghĩa trường.

Hãy xem mẫu MSDN: StructLayoutAttribute Class và phải rõ ràng hơn. Ngoài ra - tạo ứng dụng mẫu trong C++ và C# và chơi với nó để có được một hang của nó - nó sẽ mang lại lợi ích cho bạn rất nhiều.

1

Ánh xạ mặc định là struct trong C# là LayoutKind.Sequential. Điều này ngăn cản trình biên dịch tối ưu hóa bộ nhớ bằng cách sắp xếp lại các biến và đảm bảo ánh xạ chính xác.

Bạn tuy nhiên có thể nói với trình biên dịch một trật tự khác nhau của các biến bằng cách sử dụng LayoutKind.Explicit, và FieldOffsetAttribute:

[StructLayout(LayoutKind.Explicit)] 
public struct Rect 
{ 
    [FieldOffset(8)] 
    public int right; 

    [FieldOffset(4)] 
    public int top; 

    [FieldOffset(0)] 
    public int left; 

    [FieldOffset(12)] 
    public int bottom; 
} 

Giá trị của FieldOffsetAttribute chỉ ra vị trí byte trong struct của sự khởi đầu của biến.

0

Tôi có sửa đổi cấu trúc được quản lý theo điều kiện truy cập của mỗi biến và thậm chí là tên biến, nhưng tôi không thể thay đổi thứ tự của các biến?

Vâng, đó là chính xác. Cả bộ định danh truy cập, cũng như tên biến không có bất kỳ tác động nào đối với cách cấu trúc được đặt ra.

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