Managed 類型 (C++/CLI)

Visual C++ 允許透過 Managed 類型存取 .NET 功能,其可支援 Common Language Runtime 的功能,並受限於執行時間的優點和限制。

Managed 類型和主要函式

當您使用 /clr 撰寫應用程式時,函式的 main() 引數不能是 Managed 型別。

適當的簽章範例如下:

// managed_types_and_main.cpp
// compile with: /clr
int main(int, char*[], char*[]) {}

.NET Framework 相當於 C++ 原生類型

下表顯示內建 Visual C++ 類型的關鍵字,這些是 System 命名空間中預先定義型別的 別名。

Visual C++ 類型 .NET Framework 類型
void System.Void
bool System.Boolean
signed char System.SByte
unsigned char System.Byte
wchar_t System.Char
shortsigned short System.Int16
unsigned short System.UInt16
intsigned intlongsigned long System.Int32
unsigned intunsigned long System.UInt32
__int64signed __int64 System.Int64
unsigned __int64 System.UInt64
float System.Single
doublelong double System.Double

如需編譯器選項預設為 signed charunsigned char 的詳細資訊,請參閱 /J (預設 char 類型為 unsigned

原生類型巢狀實值型別的版本問題

請考慮用來建置用戶端元件的已簽署(強式名稱)元件元件。 元件包含實值型別,用於用戶端做為原生聯集、類別或陣列成員的類型。 如果元件的未來版本變更實數值型別的大小或配置,則必須重新編譯用戶端。

使用 sn.exe 建立 keyfile ( sn -k mykey.snk )。

範例

下列範例是 元件。

// nested_value_types.cpp
// compile with: /clr /LD
using namespace System::Reflection;
[assembly:AssemblyVersion("1.0.0.*"),
assembly:AssemblyKeyFile("mykey.snk")];

public value struct S {
   int i;
   void Test() {
      System::Console::WriteLine("S.i = {0}", i);
   }
};

此範例是用戶端:

// nested_value_types_2.cpp
// compile with: /clr
#using <nested_value_types.dll>

struct S2 {
   S MyS1, MyS2;
};

int main() {
   S2 MyS2a, MyS2b;
   MyS2a.MyS1.i = 5;
   MyS2a.MyS2.i = 6;
   MyS2b.MyS1.i = 10;
   MyS2b.MyS2.i = 11;

   MyS2a.MyS1.Test();
   MyS2a.MyS2.Test();
   MyS2b.MyS1.Test();
   MyS2b.MyS2.Test();
}

該範例會產生以下輸出:

S.i = 5
S.i = 6
S.i = 10
S.i = 11

註解

不過,如果您將另一個成員新增至 struct Snested_value_types.cpp 中(例如 double d; ),並在不重新編譯用戶端的情況下重新編譯元件,則結果是未處理的例外狀況(類型 System.IO.FileLoadException 為 )。

如何測試是否相等

在下列範例中,使用 C++ Managed Extensions 的相等測試是以控制碼所參考的內容為基礎。

範例

// mcppv2_equality_test.cpp
// compile with: /clr /LD
using namespace System;

bool Test1() {
   String ^ str1 = "test";
   String ^ str2 = "test";
   return (str1 == str2);
}

此程式的 IL 顯示傳回值是使用 對 op_Equality 的呼叫來實作。

IL_0012:  call       bool [mscorlib]System.String::op_Equality(string, string)

如何診斷和修正元件相容性問題

當編譯時期參考的元件版本與執行時間所參考的元件版本不符時,可能會發生各種問題。

編譯元件時,可能會使用 #using 語法參考其他元件。 編譯期間,編譯器會存取這些元件。 來自這些元件的資訊可用來做出優化決策。

不過,如果參考的元件已變更並重新編譯,也會重新編譯相依的參考元件。 否則,元件可能會變得不相容。 對新的元件版本而言,一開始有效的優化決策可能不正確。 可能會發生各種執行階段錯誤,因為這些不相容。 在這種情況下,不會產生任何特定的例外狀況。 執行時間回報失敗的方式取決於造成問題的程式碼變更本質。

只要針對產品發行的版本重建整個應用程式,這些錯誤就不應該在您的最終生產程式碼中發生問題。 發行給公眾的元件應標示為官方版本號碼,以確保避免這些問題。 如需詳細資訊,請參閱組件版本控制

診斷並修正不相容錯誤

您可能會在參考另一個元件的程式碼中遇到執行時間例外狀況或其他錯誤狀況。 如果您無法識別其他原因,問題可能是過期的元件。

  1. 首先,隔離並重現例外狀況或其他錯誤狀況。 因為過期的例外狀況而發生的問題應該可重現。

  2. 檢查應用程式中所參考之任何元件的時間戳記。

  3. 如果任何參考元件的時間戳記晚于應用程式上次編譯的時間戳記,則您的應用程式已過期。 如果已過期,請使用最新的元件重新編譯您的應用程式,並視需要編輯您的程式碼。

  4. 重新執行應用程式、執行重現問題的步驟,並確認未發生例外狀況。

範例

下列程式說明問題:它會先減少方法的存取範圍,然後嘗試在另一個元件中存取該方法,而不需重新編譯。 先編譯 changeaccess.cpp 。 這是將變更的參考元件。 然後編譯 referencing.cpp 。 它應該會成功編譯。 接下來,減少所呼叫方法的存取範圍。 使用編譯器選項 /DCHANGE_ACCESS 重新編譯 changeaccess.cpp 。 它會讓 access_me 方法 ,而不是 public ,因此無法從外部 Test 或其 protected 衍生專案呼叫。 若未重新編譯 referencing.exe ,請重新執行應用程式。 發生 。 MethodAccessException

// changeaccess.cpp
// compile with: /clr:safe /LD
// After the initial compilation, add /DCHANGE_ACCESS and rerun
// referencing.exe to introduce an error at runtime. To correct
// the problem, recompile referencing.exe

public ref class Test {
#if defined(CHANGE_ACCESS)
protected:
#else
public:
#endif

  int access_me() {
    return 0;
  }

};

以下是參考元件的來源:

// referencing.cpp
// compile with: /clr:safe
#using <changeaccess.dll>

// Force the function to be inline, to override the compiler's own
// algorithm.
__forceinline
int CallMethod(Test^ t) {
  // The call is allowed only if access_me is declared public
  return t->access_me();
}

int main() {
  Test^ t = gcnew Test();
  try
  {
    CallMethod(t);
    System::Console::WriteLine("No exception.");
  }
  catch (System::Exception ^ e)
  {
    System::Console::WriteLine("Exception!");
  }
  return 0;
}

另請參閱

使用 C++/CLI 進行 .NET 程式設計 (Visual C++)
與其他 .NET 語言的互通性 (C++/CLI)
Managed 類型 (C++/CLI)
#using 指導