This documentation is archived and is not being maintained.


Managed Extensions for C++ allows data types to be discovered, examined, and invoked at runtime through reflection. This ability is supported through the common language runtime and uses the metadata included automatically in each DLL and EXE.

Reflection is similar to run-time type information (RTTI) of native C++ but is much more powerful. Furthermore, reflection is always supported for managed types, which differs from RTTI, which must be enabled through compiler options.

Reflection allows known data types to be inspected at runtime through the reflection API. Like RTTI, this allows the names of data types to be retrieved in string form, but reflection goes much farther. For example, reflection allows the enumeration of data types in a given assembly, and the members of a given class or value type can be discovered. This is true regardless of whether the type was known or referenced at compile time. This makes reflection a useful feature for the implementation of development and code management tools and for production code.

The most common way to access reflection features is through the GetType method. This method is provided by System::Object, from which all garbage-collected classes derive.

The GetType method returns a pointer to a Type class object, which describes the type upon when the object is based. (The Type object does not contain any instance-specific information.) One such item is the full name of the type, which can be displayed as follows:

// compile with: /clr
int main()
   String* s = "sample string";
   Type* t = s->GetType();
   Console::WriteLine("full type name of '{0}' is '{1}'", 
                   s, t->FullName);
   return 0;

This code provides the following output:

full type name of 'sample string' is 'System.String'

Note that the type name includes the full scope in which the type is defined, including the namespace, and that it is displayed in .NET syntax, with a dot as the scope resolution operator.

Alternately, the Type pointer can be passed directly to Console::WriteLine for the same result:

// compile with: /clr
int main()
   String* s = "sample string";
   Console::WriteLine("full type name of '{0}' is '{1}'", 
   s, s->GetType());
   return 0;

Value types can be used with the GetType function as well, but they must be boxed first:

// compile with: /clr
int main()
   // initialize 'i' to avoid "variable used 
   // without having been initialized" warning.
   Int32 i = 100; 
   Console::WriteLine("type of i = '{0}'", __box(i)->GetType());
   return 0;

This code produces this output:

type of i = 'System.Int32'

Used in together with the __typeof operator, having an instance of the given type is not necessary:

// compile with: /clr
int main()
   Console::WriteLine("type of Int32 = '{0}'", __typeof(Int32));
   return 0;

As with the GetType method, the __typeof operator returns a pointer to a Type object, so this code indicates the type name System.Int32. isplaying type names is the most basic feature of reflection, but a potentially more useful technique is to inspect or discover the valid values for enumerated types. This can be done by using the static Enum::GetNames function, which returns an array of strings, each containing an enumeration value in text form, as demonstrated in the following example:

// compile with: /clr
__value enum Options 
  Option1, Option2, Option3

int main()
   String* names __gc[] = Enum::GetNames(__typeof(Options));

   Console::WriteLine("there are {0} options in enum '{1}'", 
               __box(names->Length), __typeof(Options));

   for (int i=0; i<names->Length; i++)
      Console::WriteLine("{0}: {1}", __box(i), names[i]);

   Options o = Option2;
   Console::WriteLine("value of 'o' is {0}", __box(o));

   return 0;

This code retrieves an array of strings that describes the value enumeration values for the Options enum and displays them in a loop. Notice the __value keyword that precedes the enum. Without this, a native enumeration is created, with which reflection will not work. The output of this program looks like this:

there are 3 options in enum 'Options'
0: Option1
1: Option2
2: Option3
value of 'o' is Option2

If a fouth option is added to the Options enumeration, this code will report the new option without recompilation, even if the enumeration is defined in a separate assembly.

The GetType object supports a number of members and properties that can be used to examine a type. This code retrieves and displays some of this information:

// compile with: /clr
int main()
   Console::WriteLine("type information for 'String':");
   Type* t = __typeof(String);

   String* assemblyName = t->Assembly->FullName;
   Console::WriteLine("assembly name: {0}", assemblyName);

   String* nameSpace = t->Namespace;
   Console::WriteLine("namespace: {0}", nameSpace);

   String* baseType = t->BaseType->FullName;
   Console::WriteLine("base type: {0}", baseType);

   bool isArray = t->IsArray;
   Console::WriteLine("is array: {0}", __box(isArray));

   bool isClass = t->IsClass;
   Console::WriteLine("is class: {0}", __box(isClass));

   return 0;

The following output is returned:

type information for 'String':
assembly name: mscorlib, Version=1.0.5000.0, Culture=neutral, 
namespace: System
base type: System.Object
is array: False
is class: True

Note that the assembly name provided is the strong name (see Strong-Named Assemblies), which includes the assembly version, culture, and signing information. Note also that the name of the namespace in which the data type is defined can be retrived, along with the name of the base class.

Reflection also allows the enumeration of types within an assembly and the members within classes. To demonstrate this feature, define a simple class:

public __gc class TestClass
   TestClass() { }
   void SimpleTestMember1() { }
   String* SimpleMember2(String* s) { return s; } 
   int TestMember(int i) { return i; }
   __property int get_Member() { return m_i; }
   __property void set_Member(int i) { m_i = i; }
   int m_i;

If the code is compiled into a DLL called TestAssembly.dll, you can then use reflection to inspect the contents of this assembly. This involves using the static reflection API function Assembly::Load to load the assembly. This function returns the address of an Assembly object that can then be quieried about the modules and types within.

int main()
   Assembly* a = 0;
      // load the assembly (do not include ".DLL" extension
      a = Assembly::Load(S"TestAssembly");
   catch (FileNotFoundException* e)
      return -1;

   Console::WriteLine("assembly info:");
   Type* typeArray __gc[] = a->GetTypes();
   Console::WriteLine("type info ({0} types):", __box(typeArray->Length));

   int totalTypes = 0;
   int totalMembers = 0;
   for (int i=0; i<typeArray->Length; i++)
      // retrieve array of member descriptions
      MemberInfo* member __gc[] = typeArray[i]->GetMembers();
      Console::WriteLine("  members of {0} ({1} members):", 
      typeArray[i]->FullName, __box(member->Length));
      for (int j=0; j<member->Length; j++)
         Console::Write("       ({0})  ", 
         __box(member[j]->MemberType)->ToString() );
         Console::Write("{0}  ", member[j]);
   Console::WriteLine("{0} total types, {1} total members",
   __box(totalTypes), __box(totalMembers));
   return 0;

The code returns the following output:

assembly info:
TestAssembly, Version=, Culture=neutral, PublicKeyToken=null
type info (1 types):
  members of TestClass (11 members):
       (Method)  Int32 GetHashCode()
       (Method)  Boolean Equals(System.Object)
       (Method)  System.String ToString()
       (Method)  Void SimpleTestMember1()
       (Method)  System.String SimpleMember2(System.String)
       (Method)  Int32 TestMember(Int32)
       (Method)  Int32 get_Member()
       (Method)  Void set_Member(Int32)
       (Method)  System.Type GetType()
       (Constructor)  Void .ctor()
       (Property)  Int32 Member
1 total types, 11 total members

Once the reflection system successfully loads the assembly, an array of Type objects is retrieved with the Assembly::GetTypes function. Each array element contains information about a different type, although in this case, only one class is defined. Using a loop, each Type in this array is queried about the type members using the Type::GetMembers function. This function returns an array of MethodInfo objects, each containing information about the member function, data member, or property in the type.

Note that the list of methods includes the functions explicitly defined in TestClass and the functions implicitly inherited from the System::Object class. As part of being described in .NET rather than in C++ syntax, properties appear as the underlying data member accessed by the get/set functions. The get/set function appear in this list as regular methods. Reflection is supported through the common language runtime, not by the C++ compiler.

Although you used this code to inspect an assembly that you defined, you can also use this code to inspect .NET assemblies. For example, if you change TestAssembly to mscorlib, then you will see a listing of every type and method defined in mscorlib.dll.

See Also

.NET Reflection Topics | System.Reflection Namespace | Managed Extensions for C++ Programming