c++ so 反射_反射 (C++/CLI)

反射 (C++/CLI)Reflection (C++/CLI)

11/04/2016

本文内容

反射允许在运行时检查已知的数据类型。Reflection allows known data types to be inspected at runtime. 反射允许枚举给定程序集中的数据类型,并且可以发现给定类或值类型的成员。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 development and code management tools.

请注意,提供的程序集名称是强名称 (请参阅 创建和使用 Strong-Named 程序集) ,其中包括程序集版本、区域性和签名信息。Note that the assembly name provided is the strong name (see Creating and Using 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 retrieved, along with the name of the base class.

访问反射功能最常见的方法是通过 GetType 方法。The most common way to access reflection features is through the GetType method. 此方法由提供 System.Object ,所有垃圾回收类都从中派生。This method is provided by System.Object, from which all garbage-collected classes derive.

备注

仅当使用 /clr: pure 或 /clr: safe 编译器选项生成 .exe 时,才允许在使用 Microsoft c + + 编译器生成的 .exe 上进行反射。Reflection on an .exe built with the Microsoft C++ compiler is only allowed if the .exe is built with the /clr:pure or /clr:safe compiler options. /Clr: pure 和 /clr: safe 编译器选项在 visual studio 2015 中已弃用,在 visual studio 2017 中不可用。The /clr:pure and /clr:safe compiler options are deprecated in Visual Studio 2015 and unavailable in Visual Studio 2017.

For more information, see System.Reflection

示例: GetTypeExample: GetType

GetType方法返回指向类对象的指针 Type ,该对象描述对象所基于的类型。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:

请注意,类型名称包括定义该类型的完整范围(包括命名空间),并以 .NET 语法显示,用点作为范围解析运算符。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.

// vcpp_reflection.cpp

// compile with: /clr

using namespace System;

int main() {

String ^ s = "sample string";

Console::WriteLine("full type name of '{0}' is '{1}'", s, s->GetType());

}

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

示例:装箱值类型Example: boxed value types

值类型也可以与函数一起使用 GetType ,但必须先将值类型装箱。Value types can be used with the GetType function as well, but they must be boxed first.

// vcpp_reflection_2.cpp

// compile with: /clr

using namespace System;

int main() {

Int32 i = 100;

Object ^ o = i;

Console::WriteLine("type of i = '{0}'", o->GetType());

}

type of i = 'System.Int32'

示例: typeidExample: typeid

与方法一样 GetType , typeid 运算符返回指向 类型 对象的指针,因此此代码指示类型名称 system.object。As with the GetType method, the typeid operator returns a pointer to a Type object, so this code indicates the type name System.Int32. 显示类型名称是反射的最基本的功能,但可能更有用的方法是检查或发现枚举类型的有效值。Displaying 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. 这可以通过使用静态 Enum:: GetNames 函数来完成,该函数返回一个字符串数组,每个字符串都包含一个文本格式的枚举值。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. 下面的示例检索一个字符串数组,该数组描述 (CLR) 枚举的 选项 的值枚举值并将它们显示在一个循环中。The following sample retrieves an array of strings that describes the value enumeration values for the Options (CLR) enum and displays them in a loop.

如果在 选项 枚举中添加了第四个选项,则此代码将报告新选项而不重新编译,即使枚举是在单独的程序集中定义的也是如此。If a fourth 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.

// vcpp_reflection_3.cpp

// compile with: /clr

using namespace System;

enum class Options { // not a native enum

Option1, Option2, Option3

};

int main() {

array^ names = Enum::GetNames(Options::typeid);

Console::WriteLine("there are {0} options in enum '{1}'",

names->Length, Options::typeid);

for (int i = 0 ; i < names->Length ; i++)

Console::WriteLine("{0}: {1}", i, names[i]);

Options o = Options::Option2;

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

}

there are 3 options in enum 'Options'

0: Option1

1: Option2

2: Option3

value of 'o' is Option2

示例: GetType 成员和属性Example: GetType members and properties

GetType对象支持多个可用于检查类型的成员和属性。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:

// vcpp_reflection_4.cpp

// compile with: /clr

using namespace System;

int main() {

Console::WriteLine("type information for 'String':");

Type ^ t = String::typeid;

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}", isArray);

bool isClass = t->IsClass;

Console::WriteLine("is class: {0}", isClass);

}

type information for 'String':

assembly name: mscorlib, Version=1.0.5000.0, Culture=neutral,

PublicKeyToken=b77a5c561934e089

namespace: System

base type: System.Object

is array: False

is class: True

示例:类型的枚举Example: enumeration of types

反射还允许枚举程序集中的类型和类中的成员。Reflection also allows the enumeration of types within an assembly and the members within classes. 若要演示此功能,请定义一个简单的类:To demonstrate this feature, define a simple class:

// vcpp_reflection_5.cpp

// compile with: /clr /LD

using namespace System;

public ref class TestClass {

int m_i;

public:

TestClass() {}

void SimpleTestMember1() {}

String ^ SimpleMember2(String ^ s) { return s; }

int TestMember(int i) { return i; }

property int Member {

int get() { return m_i; }

void set(int i) { m_i = i; }

}

};

示例:检查程序集Example: inspection of assemblies

如果上面的代码编译到名为 vcpp_reflection_6.dll 的 DLL 中,则可以使用反射来检查此程序集的内容。If the code above is compiled into a DLL called vcpp_reflection_6.dll, you can then use reflection to inspect the contents of this assembly. 这涉及到使用静态反射 API 函数 x: displayProperty% 2A? = Namewithtype> 加载程序集。This involves using the static reflection API function xref:System.Reflection.Assembly.Load%2A?displayProperty=nameWithType to load the assembly. 此函数返回 程序集 对象的地址,然后可以查询该对象中有关模块和类型的信息。This function returns the address of an Assembly object that can then be queried about the modules and types within.

反射系统成功加载程序集后,将使用函数检索 类型 对象的数组 Assembly.GetTypes 。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. 使用循环时,将使用 type:: GetMembers 函数查询此数组中的每个 类型 有关类型成员的信息。Using a loop, each Type in this array is queried about the type members using the Type::GetMembers function. 此函数返回 MethodInfo 对象的数组,每个对象都包含有关该类型中的成员函数、数据成员或属性的信息。This function returns an array of MethodInfo objects, each object containing information about the member function, data member, or property in the type.

请注意,方法的列表包括 TestClass 中显式定义的函数,以及从 System:: Object 类隐式继承的函数。Note that the list of methods includes the functions explicitly defined in TestClass and the functions implicitly inherited from the System::Object class. 作为在 .NET 中描述的一部分,而不是在 Visual C++ 语法中,属性显示为 get/set 函数访问的基础数据成员。As part of being described in .NET rather than in Visual C++ syntax, properties appear as the underlying data member accessed by the get/set functions. Get/set 函数在此列表中显示为常规方法。The get/set functions appear in this list as regular methods. 反射支持通过公共语言运行时,而不是 Microsoft c + + 编译器。Reflection is supported through the common language runtime, not by the Microsoft C++ compiler.

尽管你使用此代码来检查你定义的程序集,但你也可以使用此代码来检查 .NET 程序集。Although you used this code to inspect an assembly that you defined, you can also use this code to inspect .NET assemblies. 例如,如果将 TestAssembly 更改为 mscorlib,则会看到在 mscorlib.dll 中定义的每个类型和方法的列表。For example, if you change TestAssembly to mscorlib, then you will see a listing of every type and method defined in mscorlib.dll.

// vcpp_reflection_6.cpp

// compile with: /clr

using namespace System;

using namespace System::IO;

using namespace System::Reflection;

int main() {

Assembly ^ a = nullptr;

try {

// load assembly -- do not use file extension

// will look for .dll extension first

// then .exe with the filename

a = Assembly::Load("vcpp_reflection_5");

}

catch (FileNotFoundException ^ e) {

Console::WriteLine(e->Message);

return -1;

}

Console::WriteLine("assembly info:");

Console::WriteLine(a->FullName);

array^ typeArray = a->GetTypes();

Console::WriteLine("type info ({0} types):", typeArray->Length);

int totalTypes = 0;

int totalMembers = 0;

for (int i = 0 ; i < typeArray->Length ; i++) {

// retrieve array of member descriptions

array^ member = typeArray[i]->GetMembers();

Console::WriteLine(" members of {0} ({1} members):",

typeArray[i]->FullName, member->Length);

for (int j = 0 ; j < member->Length ; j++) {

Console::Write(" ({0})",

member[j]->MemberType.ToString() );

Console::Write("{0} ", member[j]);

Console::WriteLine("");

totalMembers++;

}

totalTypes++;

}

Console::WriteLine("{0} total types, {1} total members",

totalTypes, totalMembers);

}

如何:使用反射实现 Plug-In 组件体系结构How to: Implement a Plug-In Component Architecture using Reflection

下面的代码示例演示如何使用反射来实现简单的 "插件" 体系结构。The following code examples demonstrate the use of reflection to implement a simple "plug-in" architecture. 第一个列表是应用程序,第二个列表是插件。The first listing is the application, and the second is the plug-in. 应用程序是一种多文档窗体,该窗体使用在作为命令行参数提供的插件 DLL 中找到的任何基于窗体的类进行填充。The application is a multiple document form that populates itself using any form-based classes found in the plug-in DLL provided as a command-line argument.

The application attempts to load the provided assembly using the System.Reflection.Assembly.Load method. If successful, the types inside the assembly are enumerated using the System.Reflection.Assembly.GetTypes method. Each type is then checked for compatibility using the System.Type.IsAssignableFrom method. 在此示例中,在提供的程序集中找到的类必须从 Form 类派生,才能作为插件。In this example, classes found in the provided assembly must be derived from the Form class to qualify as a plug-in.

然后使用方法实例化兼容的类 System.Activator.CreateInstance ,该方法接受 Type 作为参数,并返回指向新实例的指针。Compatible classes are then instantiated with the System.Activator.CreateInstance method, which accepts a Type as an argument and returns a pointer to a new instance. 然后,每个新实例都附加到窗体并显示。Each new instance is then attached to the form and displayed.

请注意, Load 方法不接受包含文件扩展名的程序集名称。Note that the Load method does not accept assembly names that include the file extension. 应用程序中的 main 函数剪裁任何提供的扩展,因此下面的代码示例适用于这两种情况。The main function in the application trims any provided extensions, so the following code example works in either case.

示例Example

下面的代码定义了接受插件的应用程序。必须提供程序集名称作为第一个参数。The following code defines the application that accepts plug-ins. An assembly name must be provided as the first argument. 此程序集应包含至少一个公共 Form 派生类型。This assembly should contain at least one public Form derived type.

// plugin_application.cpp

// compile with: /clr /c

#using

#using

#using

using namespace System;

using namespace System::Windows::Forms;

using namespace System::Reflection;

ref class PluggableForm : public Form {

public:

PluggableForm() {}

PluggableForm(Assembly^ plugAssembly) {

Text = "plug-in example";

Size = Drawing::Size(400, 400);

IsMdiContainer = true;

array^ types = plugAssembly->GetTypes( );

Type^ formType = Form::typeid;

for (int i = 0 ; i < types->Length ; i++) {

if (formType->IsAssignableFrom(types[i])) {

// Create an instance given the type description.

Form^ f = dynamic_cast

(Activator::CreateInstance(types[i]));

if (f) {

f->Text = types[i]->ToString();

f->MdiParent = this;

f->Show();

}

}

}

}

};

int main() {

Assembly^ a = Assembly::LoadFrom("plugin_application.exe");

Application::Run(gcnew PluggableForm(a));

}

示例Example

下面的代码定义了从派生的三个类 Form 。The following code defines three classes derived from Form. 当生成的程序集名称的名称传递到上一列表中的可执行文件时,将发现并实例化这三个类中的每个类,尽管在编译时它们都是未知的。When the name of the resulting assembly name is passed to the executable in the previous listing, each of these three classes will be discovered and instantiated, despite the fact that they were all unknown to the hosting application at compile time.

// plugin_assembly.cpp

// compile with: /clr /LD

#using

#using

#using

using namespace System;

using namespace System::Windows::Forms;

using namespace System::Reflection;

using namespace System::Drawing;

public ref class BlueForm : public Form {

public:

BlueForm() {

BackColor = Color::Blue;

}

};

public ref class CircleForm : public Form {

protected:

virtual void OnPaint(PaintEventArgs^ args) override {

args->Graphics->FillEllipse(Brushes::Green, ClientRectangle);

}

};

public ref class StarburstForm : public Form {

public:

StarburstForm(){

BackColor = Color::Black;

}

protected:

virtual void OnPaint(PaintEventArgs^ args) override {

Pen^ p = gcnew Pen(Color::Red, 2);

Random^ r = gcnew Random( );

Int32 w = ClientSize.Width;

Int32 h = ClientSize.Height;

for (int i=0; i<100; i++) {

float x1 = w / 2;

float y1 = h / 2;

float x2 = r->Next(w);

float y2 = r->Next(h);

args->Graphics->DrawLine(p, x1, y1, x2, y2);

}

}

};

如何:使用反射枚举程序集中的数据类型How to: Enumerate Data Types in Assemblies using Reflection

下面的代码演示了使用的公共类型和成员的枚举 System.Reflection 。The following code demonstrates the enumeration of public types and members using System.Reflection.

给定程序集的名称,无论是在本地目录中还是 GAC 中,以下代码都尝试打开程序集并检索说明。Given the name of an assembly, either in the local directory or in the GAC, the code below attempts to open the assembly and retrieve descriptions. 如果成功,则每个类型都将与其公共成员一起显示。If successful, each type is displayed with its public members.

Note that System.Reflection.Assembly.Load requires that no file extension is used. 因此,使用 "mscorlib.dll" 作为命令行参数将失败,而仅使用 "mscorlib" 将导致显示 .NET Framework 类型。Therefore, using "mscorlib.dll" as a command-line argument will fail, while using just "mscorlib" will result the display of the .NET Framework types. 如果未提供任何程序集名称,则代码将检测并报告当前程序集中的类型 (由此代码) 生成的 EXE。If no assembly name is provided, the code will detect and report the types within the current assembly (the EXE resulting from this code).

示例Example

// self_reflection.cpp

// compile with: /clr

using namespace System;

using namespace System::Reflection;

using namespace System::Collections;

public ref class ExampleType {

public:

ExampleType() {}

void Func() {}

};

int main() {

String^ delimStr = " ";

array^ delimiter = delimStr->ToCharArray( );

array^ args = Environment::CommandLine->Split( delimiter );

// replace "self_reflection.exe" with an assembly from either the local

// directory or the GAC

Assembly^ a = Assembly::LoadFrom("self_reflection.exe");

Console::WriteLine(a);

int count = 0;

array^ types = a->GetTypes();

IEnumerator^ typeIter = types->GetEnumerator();

while ( typeIter->MoveNext() ) {

Type^ t = dynamic_cast(typeIter->Current);

Console::WriteLine(" {0}", t->ToString());

array^ members = t->GetMembers();

IEnumerator^ memberIter = members->GetEnumerator();

while ( memberIter->MoveNext() ) {

MemberInfo^ mi = dynamic_cast(memberIter->Current);

Console::Write(" {0}", mi->ToString( ) );

if (mi->MemberType == MemberTypes::Constructor)

Console::Write(" (constructor)");

Console::WriteLine();

}

count++;

}

Console::WriteLine("{0} types found", count);

}

请参阅See also

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值