2009-08-19 14 views
46

Làm thế nào để bạn chuyển đổi Hệ thống :: Chuỗi thành chuỗi: chuỗi trong C++ .NET?C++ .NET chuyển đổi Hệ thống :: Chuỗi thành tiêu đề :: chuỗi

+5

Đừng. Chuyển đổi sang std :: wstring. System.String là Unicode, không phải ASCII – MSalters

+6

@MSalters Huh? Dường như bạn có ấn tượng rằng chuyển đổi không bao gồm bản dịch hoặc mọi người luôn có thể chọn những API nào họ sẽ tương tác với ... –

Trả lời

55

Có cú pháp sạch hơn nếu bạn đang sử dụng một phiên bản gần đây của .net

#include "stdafx.h" 
#include <string> 

#include <msclr\marshal_cppstd.h> 

using namespace System; 

int main(array<System::String ^> ^args) 
{ 
    System::String^ managedString = "test"; 

    msclr::interop::marshal_context context; 
    std::string standardString = context.marshal_as<std::string>(managedString); 

    return 0; 
} 

này cũng cung cấp cho bạn tốt hơn dọn dẹp khi đối mặt với trường hợp ngoại lệ.

Có một msdn article cho các chuyển đổi khác nhau

+0

Điều này cũng có thể xử lý mã hóa từ UTF-16 (mặc định .Net) thành UTF-8 (std :: string) không? – zak

7
stdString = toss(systemString); 

    static std::string toss(System::String^s) 
    { 
    // convert .NET System::String to std::string 
    const char* cstr = (const char*) (Marshal::StringToHGlobalAnsi(s)).ToPointer(); 
    std::string sstr = cstr; 
    Marshal::FreeHGlobal(System::IntPtr((void*)cstr)); 
    return sstr; 
    } 
+1

Đây là cú pháp cũ hơn. Tôi thích cái mà Colin gợi ý ở trên. – orad

+0

Nếu sstr() ném thì sao? Điều đó sẽ không khiến cstr trở thành một sự rò rỉ? –

25

Và để đáp lại "cách dễ dàng hơn" trong các phiên bản sau này của C++/CLI, bạn có thể làm điều đó mà không có sự marshal_context. Tôi biết điều này làm việc trong Visual Studio 2010; không chắc chắn về điều đó trước đó.


#include "stdafx.h" 
#include <string> 

#include <msclr\marshal_cppstd.h> 

using namespace msclr::interop; 

int main(array<System::String ^> ^args) 
{ 
    System::String^ managedString = "test"; 

    std::string standardString = marshal_as<std::string>(managedString); 

    return 0; 
} 

+1

Nhìn vào bài viết MSDN Collin được liên kết để xem khi nào nên sử dụng marshal_as và khi nào thì sử dụng marshal_context. Nói chung, marshal_context là cần thiết khi các tài nguyên không được quản lý cần phải làm sạch. – rotti2

+2

Bài viết nói rằng chỉ cần một ngữ cảnh nếu kiểu gốc không có một destructor để làm sạch riêng của nó. Vì vậy, trong trường hợp 'std :: string', điều này có cần thiết không? –

+1

Ngữ cảnh không cần thiết cho 'std :: string'. Bối cảnh chỉ cần thiết khi marshaling từ một loại bọc đến một loại chưa được mở (tức là con trỏ thô). Như được liệt kê trong [Tổng quan về Marshaling trong C++] (http://msdn.microsoft.com/en-us/library/bb384865.aspx), chỉ có ba trường hợp mà bối cảnh là cần thiết. –

3

tôi đã có quá nhiều lỗi mơ hồ hiển thị với các câu trả lời trên (vâng, tôi là một C++ Noob)

này làm việc cho tôi để gửi chuỗi từ C# C++ CLI

C#

bool result; 
result = mps.Import(mpsToolName); 

C++ CLI

chức năng:

bool ManagedMPS::Import(System::String^ mpsToolNameTest) 
std::string mpsToolName; 
mpsToolName = toStandardString(mpsToolNameTest); 

chức năng làm việc từ chuyển đổi chuỗi^để std :: string

static std::string toStandardString(System::String^ string) 
{ 
using System::Runtime::InteropServices::Marshal; 
System::IntPtr pointer = Marshal::StringToHGlobalAnsi(string); 
char* charPointer = reinterpret_cast<char*>(pointer.ToPointer()); 
std::string returnString(charPointer, string->Length); 
Marshal::FreeHGlobal(pointer); 
return returnString; 
} 

VỀ NGHIÊN CỨU THÊM, dường như đây là sạch hơn và an toàn hơn.

Tôi đã chuyển sang sử dụng phương pháp này để thay thế.

std::string Utils::ToUnmanagedString(String^ stringIncoming) 
{ 
    std::string unmanagedString = marshal_as<std::string>(stringIncoming); 
    return unmanagedString; 
} 
+0

Vậy làm cách nào bạn quản lý để loại bỏ tất cả các lỗi không rõ ràng của IServiceProvider? –

+0

Tôi không nhớ đã nhận được các lỗi đó. Tôi mới vào C++, bây giờ tôi đang ở trên một hợp đồng/dự án với công ty khác .... xin lỗi tốt nhất của may mắn. –

0

Tạo Windows Runtime Component bạn có thể sử dụng:

String^ systemString = "Hello"; 
std::wstring ws1(systemString ->Data()); 
std::string standardString(ws1.begin(), ws1.end()); 
6

C# sử dụng định dạng UTF16 cho chuỗi của nó.
Vì vậy, ngoài việc chuyển đổi các loại, bạn cũng nên ý thức về định dạng thực tế của chuỗi.

Khi biên dịch cho Bộ ký tự nhiều byte Visual Studio và API Win giả định UTF8 (Mã hóa cửa sổ thực tế là Windows-28591).
Khi biên dịch cho Bộ ký tự Unicode Visual studio và API Win giả định UTF16.

Vì vậy, bạn cũng phải chuyển đổi chuỗi từ định dạng UTF16 sang UTF8 và không chỉ chuyển thành chuỗi std ::.
Điều này sẽ trở nên cần thiết khi làm việc với các định dạng đa ký tự như một số ngôn ngữ không phải latin.

Ý tưởng là quyết định rằng std::wstringluôn là đại diện cho UTF16.
std::stringluôn là đại diện cho UTF8.

Điều này không được thực thi bởi trình biên dịch, đó là một chính sách tốt để có.

#include "stdafx.h" 
#include <string> 

#include <msclr\marshal_cppstd.h> 

using namespace System; 

int main(array<System::String ^> ^args) 
{ 
    System::String^ managedString = "test"; 

    msclr::interop::marshal_context context; 

    //Actual format is UTF16, so represent as wstring 
    std::wstring utf16NativeString = context.marshal_as<std::wstring>(managedString); 

    //C++11 format converter 
    std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> convert; 

    //convert to UTF8 and std::string 
    std::string utf8NativeString = convert.to_bytes(utf16NativeString); 

    return 0; 
} 

Hoặc có nó trong một cú pháp nhỏ gọn hơn:

int main(array<System::String ^> ^args) 
{ 
    System::String^ managedString = "test"; 

    msclr::interop::marshal_context context; 
    std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> convert; 

    std::string utf8NativeString = convert.to_bytes(context.marshal_as<std::wstring>(managedString)); 

    return 0; 
} 
Các vấn đề liên quan