2009-07-25 80 views
8

Tôi đang cố gắng hiểu tại sao ví dụ thứ hai bên dưới hoạt động mà không có vấn đề gì, nhưng ví dụ đầu tiên cho tôi ngoại lệ bên dưới. Dường như với tôi rằng cả hai ví dụ nên đưa ra một ngoại lệ dựa trên mô tả. Ai có thể khai sáng cho tôi không?C# StructLayout.Explicit Câu hỏi

Unhandled Exception: System.TypeLoadException: Không thể loại tải 'StructTest.OuterType' từ lắp ráp 'StructTest, Version = 1.0.0.0, Văn hóa = trung tính, PublicKeyToken = null' vì nó có chứa một trường đối tượng tại số bù trừ 0 được căn chỉnh không chính xác hoặc được chồng lấp bởi trường không đối tượng.
tại StructTest.Program.Main (Chuỗi [] args) Nhấn phím bất kỳ để tiếp tục. . .

Ví dụ 1

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Runtime.InteropServices; 
using System.Text; 

namespace StructTest 
{ 
    [StructLayout(LayoutKind.Sequential, Pack = 1)] 
    struct InnerType 
    { 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)] 
     char[] buffer; 
    } 

    [StructLayout(LayoutKind.Explicit)] 
    struct OuterType 
    { 
     [FieldOffset(0)] 
     int someValue; 

     [FieldOffset(0)] 
     InnerType someOtherValue; 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      OuterType t = new OuterType(); 
      System.Console.WriteLine(t); 
     } 
    } 
} 

Ví dụ 2

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Runtime.InteropServices; 
using System.Text; 

namespace StructTest 
{ 
    [StructLayout(LayoutKind.Sequential, Pack = 1)] 
    struct InnerType 
    { 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)] 
     char[] buffer; 
    } 

    [StructLayout(LayoutKind.Explicit)] 
    struct OuterType 
    { 
     [FieldOffset(4)] 
     private int someValue; 

     [FieldOffset(0)] 
     InnerType someOtherValue; 

    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      OuterType t = new OuterType(); 
      System.Console.WriteLine(t); 
     } 
    } 
} 

Trả lời

9

Bộ thực thi ngôn ngữ chung chứa một xác minh rằng đảm bảo mã chạy (thể xác minh được IL) có thể không có khả năng bộ nhớ bị hỏng trong môi trường được quản lý. Điều này ngăn bạn khai báo một cấu trúc như vậy trong đó các trường chồng lên nhau. Về cơ bản, cấu trúc của bạn chứa hai thành viên dữ liệu. Một số nguyên (là 4 byte) và một số nguyên nguyên (kích thước con trỏ). Trên một CLR 32 bit, trong đó bạn có thể đang chạy mã của bạn, các char[] sẽ mất 4 byte vì vậy nếu bạn đặt số nguyên ít hơn bốn byte đi từ đầu của cấu trúc, bạn sẽ có các trường chồng chéo. Thật thú vị khi lưu ý rằng cả hai đoạn mã của bạn đều thất bại trong thời gian chạy 64 bit, vì kích thước con trỏ là 8 byte.

+0

Tôi hiểu, vì vậy nếu tôi muốn thực hiện điều này một cách chính xác để nó hoạt động chính xác trên máy 32 hoặc 64 bit, tôi cần phải sử dụng bù 8 và 0 tương ứng, đúng không? Vấn đề là những gì tôi thực sự muốn tạo ra là một công đoàn và có vẻ như điều này sẽ kết thúc không phải là một nếu tôi không thể sử dụng cùng một bù đắp. –

+0

Có. Nó sẽ làm việc trên x64 CLR với offset 8 và 0. Lưu ý rằng trong khi đoạn mã hoạt động, nếu bạn đang làm điều này trong một ứng dụng thế giới thực, có thể bạn đang giao tiếp với một số công cụ không được quản lý, điều này có thể sẽ xảy ra sai số chính xác. Nếu bạn đặt nó thành 8, nó có thể thất bại trên các máy 32 bit (không phải đoạn mã này, nhưng mã không được quản lý mà bạn đang giao tiếp). –

+1

Nhân tiện, bạn ** có thể ** có các trường chồng chéo nếu chúng thuộc loại * không được quản lý *, nhưng một mảng .NET là một kiểu tham chiếu (không thể được coi là kiểu không được quản lý cho mỗi thông số C#). Vì vậy, bạn không thể có một loại tham chiếu như là một thành viên của một công đoàn trong C#. Nếu bạn thực sự cần điều này, bạn nên xem xét việc sử dụng những thứ như các loại con trỏ như các thành viên struct thay vì một mảng. –

1

Tôi figured tôi sẽ trả lời với các giải pháp tôi được sử dụng để tạo ra các công đoàn - đó là ý định ban đầu của tôi. Tôi đã sử dụng một cấu trúc không an toàn và một mảng cố định và sau đó sử dụng một thuộc tính để tương tác với mảng cố định. Tôi tin rằng điều này nên làm những gì tôi muốn.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Runtime.InteropServices; 
using System.Text; 

namespace StructTest 
{ 

    [StructLayout(LayoutKind.Explicit)] 
    unsafe struct OuterType 
    { 
     private const int BUFFER_SIZE = 100; 

     [FieldOffset(0)] 
     private int transactionType; 

     [FieldOffset(0)] 
     private fixed byte writeBuffer[BUFFER_SIZE]; 

     public int TransactionType 
     { 
      get { return transactionType; } 
      set { transactionType = value; } 
     } 

     public char[] WriteBuffer 
     { 
      set 
      { 
       char[] newBuffer = value; 

       fixed (byte* b = writeBuffer) 
       { 
        byte* bptr = b; 
        for (int i = 0; i < newBuffer.Length; i++) 
        { 
         *bptr++ = (byte) newBuffer[i]; 
        } 
       } 
      } 

      get 
      { 
       char[] newBuffer = new char[BUFFER_SIZE]; 

       fixed (byte* b = writeBuffer) 
       { 
        byte* bptr = b; 
        for (int i = 0; i < newBuffer.Length; i++) 
        { 
         newBuffer[i] = (char) *bptr++; 
        } 
       } 

       return newBuffer; 
      } 
     } 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      OuterType t = new OuterType(); 
      System.Console.WriteLine(t); 
     } 
    } 
}