2013-04-15 102 views
7

我花了很多時間處理非託管代碼,並在.NET中調用平臺。下面的代碼演示了一些讓我感到困惑的問題,那就是如何將非託管數據映射到.NET中的託管對象。將非託管數據映射到.NET中的託管結構

在這個例子中,我將使用RECT結構:

C++ RECT實現(非託管的Win32 API)

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

C#RECT實現(託管的.NET/C#)

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

好吧,所以我的C#等效應該工作,對?我的意思是,所有變量與C++結構的順序相同,並且它使用相同的變量名稱。

我對LayoutKind.Sequential的假設意味着非託管數據按照它出現在C++結構中的相同順序映射到託管對象。即數據將被映射,從左開始,然後從頂部開始,然後到右側,然後從底部開始。

在此基礎上,我應該能夠修改我的C#結構...

C#RECT實現(有點清潔劑)

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

那麼,如果該變量在聲明的情況錯誤的順序?據推測,這會把座標搞砸,因爲它們不會再映射到正確的東西上了?

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

在猜測,這將映射像這樣:

頂部=左

右=頂部

底部=右

左=底部

所以我的問題很簡單,我的假設是否正確,我可以根據每個變量的訪問說明符,甚至是變量名稱來修改託管結構,但是我無法更改變量的順序?

回答

7

如果您確實想要更改成員變量的順序,可以使用FieldOffsetAttribute來完成。只是讓它不那麼可讀。

您還需要將您的StructLayout設置爲LayoutKind.Explicit以指示您自己設置偏移量。

例子:

[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

優秀的答案。簡明易懂。 +1 – series0ne

+0

你真的真的不想這樣做。 –

2

是,似乎你的思維是OK。 StructLayout(LayoutKind.Sequential)是應用於C#struct的默認值,因此您甚至不需要執行此操作。但是如果你想要有不同的字段順序,你可以通過使用StructLayout(LayoutKind.Explicite)來實現,然後將FieldOffset屬性應用到每個字段 - 這是更好的方法,因爲你可以解釋什麼是隱含的,不再依賴於可以輕鬆地像字段定義順序一樣改變。

看看MSDN示例:StructLayoutAttribute Class它應該更清晰。另外 - 用C++和C#創建示例應用程序,並使用它來獲取它的一個竅門 - 它會大大受益。

1

C#中struct的默認映射是LayoutKind.Sequential。這可以防止編譯器通過重新排列變量來優化內存並確保正確的映射。

您可以但是告訴編譯器不同的順序變量的使用LayoutKind.ExplicitFieldOffsetAttribute

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

FieldOffsetAttribute的值表示變量開始的結構中的字節位置。

0

我是在我的假設是正確的,我可以在每個變量的訪問說明符,甚至變量名的條款修改的管理結構,但我不能改變變量的順序?

是的,這是正確的。訪問說明符和變量名都不影響結構佈局的方式。