2009-10-16 30 views
7

Dưới đây là một chương trình C# mà cố gắng Marshal.SizeOf trên một vài loại khác nhau:Marshalling NET kiểu generic

using System; 
using System.Runtime.InteropServices; 

[StructLayout(LayoutKind.Sequential)] 
class AClass { } 

[StructLayout(LayoutKind.Sequential)] 
struct AStruct { } 

[StructLayout(LayoutKind.Sequential)] 
class B { AClass value; } 

[StructLayout(LayoutKind.Sequential)] 
class C<T> { T value; } 

class Program 
{ 
    static void M(object o) { Console.WriteLine(Marshal.SizeOf(o)); } 

    static void Main() 
    { 
     M(new AClass()); 
     M(new AStruct()); 
     M(new B()); 
     M(new C<AStruct>()); 
     M(new C<AClass>()); 
    } 
} 

Bốn cuộc gọi đầu tiên đến M() thành công, nhưng trên người cuối cùng, sizeof ném một ArgumentException:

"Type 'C`1[AClass]' cannot be marshaled as an unmanaged structure; no meaningful size or offset can be computed." 

Tại sao? Cụ thể, tại sao SizeOf choke trên C<AClass>, nhưng không phải trên B hoặc trên C<AStruct>?


EDIT: Bởi vì nó đã được hỏi về trong các ý kiến, đây là "thực tế" Vấn đề truyền cảm hứng cho câu hỏi chủ yếu mang tính học thuật này: Tôi gọi vào một API C mà về cơ bản là một C chức năng hoạt động trên (con trỏ đến) nhiều loại cấu trúc C đơn giản khác nhau. Tất cả có chứa một tiêu đề chung theo sau là một trường, nhưng loại trường đó khác nhau trong các cấu trúc khác nhau. Cờ trong tiêu đề cho biết loại trường. (Lạ, vâng, nhưng đó là những gì tôi phải làm việc).

Nếu tôi có thể xác định một generic loại đơn C<T> và một đơn C# extern khai M(C<T>), và sau đó gọi M(C<int>) trên cùng một dòng, và M(C<double>) ngày khác, tôi muốn có một giải pháp interop ngắn và ngọt ngào. Nhưng với câu trả lời của JaredPar, có vẻ như tôi phải tạo một kiểu C# riêng cho mỗi cấu trúc (mặc dù thừa kế có thể cung cấp tiêu đề chung).

+0

Ngoại lệ nào được ném? –

+0

ArgumentException, với thông điệp ông đã dán. –

+0

@Philipp: chỉ cần chỉnh sửa để làm rõ điều đó, cảm ơn. – Gabriel

Trả lời

7

Generics dưới dạng quy tắc không được hỗ trợ trong bất kỳ trường hợp tương tác nào. Cả hai P/Invoke và COM Interop sẽ thất bại nếu bạn cố gắng để sắp xếp một loại chung hoặc giá trị. Do đó tôi mong đợi Marshal.SizeOf để được kiểm tra hoặc không được hỗ trợ cho kịch bản này vì nó là một hàm nguyên soái cụ thể.

0

Không biết kích thước của đối tượng tổng hợp T sẽ có (nó sẽ là kích thước của một con trỏ nếu T là kiểu tham chiếu và hầu hết mọi giá trị nếu đó là loại giá trị).

Tôi nghĩ rằng bạn có thể giải quyết vấn đề này bằng cách đặt thuộc tính MarshalAs trên trường 'giá trị' chỉ định loại phù hợp nhất (ví dụ: Unmanagedtype.SysInt). Lưu ý rằng nó vẫn sẽ không hoạt động đối với các loại không được biến đổi (tức là các loại cho phép bù trừ kích thước và kích thước trường).

Nhưng AFAIK, không nên sử dụng Generics trong interop.

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