2011-10-12 22 views
10

Vì vậy, tôi có một chức năng, được viết bằng C++, trông như thế này ...Tại sao C# và VB.NET ngầm hoàn toàn char * khác nhau?

extern "C" __declspec(dllexport) int __stdcall SomeFunction(char *theData) 
{ 
    // stuff 
} 

... và tôi đang sử dụng nó trong dự án hiện tại của tôi (viết bằng C#). Có những dự án khác sử dụng chức năng này viết bằng VB, nhìn như thế này:

Public Declare Function SomeFunction Lib "MyDLL.dll" _ 
    Alias "[email protected]" (ByVal theData As String) As Integer 

Vì vậy, tôi cố gắng viết một tương đương trong C#, nhưng thấy rằng việc sử dụng các loại chuỗi không thực sự làm việc cho tôi - chuỗi sẽ quay trở lại với cùng một dữ liệu tôi đã truyền vào. Tôi đã thử sử dụng "ref string" thay vì chuyển chuỗi bằng cách tham chiếu và tôi bị vi phạm quyền truy cập bộ nhớ.

Sau khi thực hiện một số đào, tôi thấy rằng đây là việc thực hiện đúng trong C#:

[DllImport("MyDLL.dll", EntryPoint = "[email protected]")] 
public static extern int SomeFunction(StringBuilder theData); 

Bây giờ tôi biết rằng VB.NET và C# khá khác nhau, nhưng tôi cho rằng tôi luôn luôn giả định rằng chuỗi là chuỗi . Nếu một ngôn ngữ có thể sắp xếp theo thứ tự char* thành String thì tại sao người khác lại không thể yêu cầu một lớp khác?

(chỉnh sửa tiêu đề để rõ ràng)

+0

Có thể thú vị khi xem cả hai phiên bản với JustDecompile hoặc .NET Reflector. –

Trả lời

6

Bây giờ tôi biết rằng VB.NET và C# khá khác nhau, nhưng tôi cho rằng tôi luôn luôn giả định rằng chuỗi là chuỗi

Strings là immutable trong .net. Hãy tự hỏi tại sao việc sử dụng loại dữ liệu bất biến có thể dẫn đến việc thay đổi giá trị của một loại dữ liệu không thay đổi. Điều đó không xảy ra đối với các chức năng bình thường, chỉ dành cho Declare.

Tôi đoán tất cả phải làm với việc duy trì khả năng tương thích ngược với các câu lệnh Declare từ VB6 cổ điển đã được thực hiện theo cách này. Theo tôi, cừu đen ở đây là mã VB.net chứ không phải mã C#.

+0

Ngoài ra, chỉ 'Declare' thực hiện điều này.'' không (VB làm những điều buồn cười với các tham số ByRef để cho phép bạn truyền vào các thuộc tính và hằng số, nhưng đây không phải là một trong số chúng) – Random832

+1

+1. Điều này là hoàn toàn ** cho khả năng tương thích ngược ** với câu lệnh 'Declare' của VB6. Trong mã VB.Net mới, bạn có thể thích ''. Trong sự khôn ngoan của họ, các nhà thiết kế VB6 đã quyết định 'ByVal As String' trong một VB6' Declare' sẽ tương đương với một '' char * '. Đằng sau thời gian chạy VB6 tạo ra một bản sao của chuỗi Unicode gốc trong định dạng "ANSI" theo trang mã Windows hiện tại, và chuyển địa chỉ của bản sao cho tệp DLL. Để hoàn thành, đây là [tài liệu Microsoft VB6 gốc] (http://vb.mvps.org/tips/vb5dll.asp) về tích hợp các tệp DLL với VB6. – MarkJ

3

Vì chúng là các ngôn ngữ khác nhau. VB.NET có thể rất nhiều thứ mà C# không thể vì nhiều lý do. Tôi không thấy vấn đề thành thật.

Tôi nên thêm bạn có thể chỉ cần thực hiện ref char [] và nó sẽ hoạt động. Một vấn đề tôi thấy là các quy ước gọi điện của bạn không khớp.

Vì vậy, đó cũng có thể là lý do khiến bạn gặp lỗi ngoại lệ bộ nhớ.

+0

Quy ước gọi điện là tốt, 'stdcall' trong tất cả các mã ở trên. AV là vì 'chuỗi ref' đơn giản không khớp với' char * '. Phải sử dụng 'StringBuilder' trong C# cho điều đó. Không có cách nào mà mã nguồn gốc có thể xây dựng một đối tượng String .net hợp lệ. –

0

Vì chuỗi là bất biến để bắt đầu, tôi đoán rằng VB bằng cách nào đó sẽ thực hiện cuộc gọi để cho phép bộ đệm được sửa đổi bởi hàm. Có lẽ bên trong VB thực sự cũng đang đi qua một StringBuilder.

Tôi sẽ không ngạc nhiên nếu đây là cuộc gọi thiết kế của nhóm VB để thực hiện các cuộc gọi API giống VB6 hơn.

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