2009-04-10 32 views
26

Tôi đã có chức năng sau:C#: Làm thế nào để vượt qua null cho một hàm mong đợi một ref?

public static extern uint FILES_GetMemoryMapping(
    [MarshalAs(UnmanagedType.LPStr)] string pPathFile, 
    out ushort Size, 
    [MarshalAs(UnmanagedType.LPStr)] string MapName, 
    out ushort PacketSize, 
    ref Mapping oMapping, 
    out byte PagesPerSector); 

Mà tôi muốn gọi như thế này:

FILES_GetMemoryMapping(MapFile, out size, MapName, 
    out PacketSize, null, out PagePerSector); 

Thật không may, tôi không thể vượt qua null trong một lĩnh vực đòi hỏi phải gõ ref Mapping và không bỏ tôi đã thử sửa lỗi này.

Mọi đề xuất?

+0

Bản sao có thể có của [Làm cách nào để xử lý các đối số struct C++ tùy chọn trong C#] (https://stackoverflow.com/questions/47997942/how-do-i-handle-optional-c-dll-struct-arguments- in-c-sharp) – River

Trả lời

30

Tôi giả định rằng Mapping là một cấu trúc? Nếu vậy bạn có thể có hai phiên bản của nguyên mẫu FILES_GetMemoryMapping() với các chữ ký khác nhau. Đối với tình trạng quá tải thứ hai mà bạn muốn vượt qua null, làm cho các tham số một IntPtr và sử dụng IntPtr.Zero

public static extern uint FILES_GetMemoryMapping(
    [MarshalAs(UnmanagedType.LPStr)] string pPathFile, 
    out ushort Size, 
    [MarshalAs(UnmanagedType.LPStr)] string MapName, 
    out ushort PacketSize, 
    IntPtr oMapping, 
    out byte PagesPerSector); 

Gọi dụ:

FILES_GetMemoryMapping(MapFile, out size, MapName, 
    out PacketSize, IntPtr.Zero, out PagePerSector); 

Nếu Mapping thực sự là một lớp thay vì một cấu trúc, chỉ cần thiết lập giá trị null trước khi truyền nó xuống.

+0

Hoạt động như một sự quyến rũ! – Nick

+3

Và những gì bạn đề nghị nếu bạn có một chức năng với 8 con trỏ đến cấu trúc và bất kỳ của chúng có thể được null? Tôi có nên viết 256 tình trạng quá tải không? Sử dụng loại giá trị nullable sẽ biến giả hoạt động? – Calmarius

+0

@Calmarius Tại sao không chỉ viết một định nghĩa thay thế tất cả 'ref ' bằng 'IntPtr'? Có, nó ít an toàn hơn, nhưng có vẻ như nếu bạn đối phó với P/Gọi sự an toàn mã đã không phải là vấn đề. – SerG

6

Một cách là tạo ra một biến giả, gán nó null, và thông qua đó vào.

2
Mapping oMapping = null; 

FILES_GetMemoryMapping(MapFile, out size, MapName, out PacketSize, ref oMapping, out PagePerSector); 
+1

Lập bản đồ thực sự là cấu trúc nên tôi không thể đặt thành giá trị rỗng. – Nick

+0

@Nick, xem câu trả lời của tôi cho trường hợp cấu trúc – JaredPar

+3

Tôi nghĩ rằng điều này bỏ lỡ điểm. Đôi khi các hàm có tham số ref mà bạn không quan tâm. Có để xác định các biến vô dụng mã lộn xộn và gây phiền nhiễu. –

23

Lý do bạn không thể vượt qua null là do thông số ref được trình biên dịch C# xử lý đặc biệt. Mọi tham số ref phải là tham chiếu có thể được chuyển đến hàm bạn đang gọi. Vì bạn muốn vượt qua null trình biên dịch từ chối cho phép điều này vì bạn không cung cấp tham chiếu mà hàm đang mong đợi có.

Tùy chọn thực sự duy nhất của bạn là tạo biến cục bộ, đặt thành null và chuyển tiếp. Trình biên dịch sẽ không cho phép bạn làm nhiều hơn thế.

1

Trong khi @ của answer JaredPar chắc chắn là đúng câu trả lời, có khác câu trả lời: unsafe mã và con trỏ:

unsafe { 
    Mapping* nullMapping = null; 
    FILES_GetMemoryMapping(
      MapFile, 
      out size, 
      MapName, 
      out PacketSize, 
      ref *nullMapping, // wat? 
      out PagePerSector); 
} 

Đó trông như nó nên thất bại trong thời gian chạy, nhưng nó doesn' t, bởi vì các ref* hủy lẫn nhau, và giá trị kết quả của ref *nullMapping là con trỏ rỗng, đó là những gì FILES_GetMemoryMapping() sẽ nhận được cho tham số đó.

Đây có thể không phải là ý tưởng hay, nhưng đó là có thể.

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