当前位置: 首页 > news >正文

C++ 中的反射

http://msdn.microsoft.com/zh-cn/library/y0114hz2.aspx

更新:2007 年 11 月

反射允许在运行时检查已知数据类型。例如,反射允许使用给定程序集中的数据类型的枚举,并且可以发现给定类或值类型中的成员。无论类型是否已知或者在编译时被引用,都是如此。这使反射成为开发和代码管理工具的一项有用功能。

请注意,所提供的程序集名称是强名称(请参见具有强名称的程序集),其中包括程序集版本、区域性和签名信息。另请注意,可以检索在其中定义数据类型的命名空间的名称以及基类的名称。

若要访问反射功能,最常见的方式是通过GetType方法。此方法由System::Object提供,所有垃圾回收类都从其派生。

如果 .exe 是用/clr:pure/clr:safe编译器选项生成的,允许使用用 Visual C++ 编译器生成的 .exe 上的反射。有关更多信息,请参见/clr(公共语言运行库编译)。

此节中的主题:

  • 如何:使用反射实现插件组件结构

  • 如何:使用反射枚举程序集中的数据类型

有关更多信息,请参见

  • 反射

  • System.Reflection 命名空间

示例

GetType方法返回指向Type类对象的指针,该类对象描述对象所基于的类型。(“Type”对象不包含任何实例特定信息。) 类型的全名就是这样的对象,它可能显示如下:

请注意,类型名称包括整个类型定义范围(包括命名空间),并且以 .NET 语法显示(以点号作为范围解析运算符)。

// 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'

值类型也可以与GetType函数一起使用,但它们必须首先装箱。

// 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'

GetType方法一样,typeid运算符将返回一个指向“Type”对象的指针,所以此代码指示类型名System.Int32。反射的最基本功能是显示类型名,但是可能更有用的技术是检查或发现枚举类型的有效值。这可以通过使用静态Enum::GetNames函数来实现,该函数返回一个字符串数组,每个字符串包含文本形式的枚举值。 下面的示例检索一个字符串数组,它描述“Options”(CLR) 枚举的值枚举值并在一个循环中显示这些值。

如果向“Options”枚举添加第四个选项,此代码将在不重新编译的情况下报告新的选项(即使该枚举是在单独的程序集中定义的)。

// vcpp_reflection_3.cpp
// compile with: /clr
using namespace System;

enum class Options {   // not a native enum
   Option1, Option2, Option3
};

int main() {
   array<String^>^ 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对象支持大量可用来检查类型的成员和属性。此代码检索并显示此信息中的一部分:

// 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

反射还允许枚举程序集内的类型和类中的成员。为了说明此功能,请定义一个简单类:

// 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; }
   }
};

如果已将上面的代码编译到称为 vcpp_reflection_6.dll 的 DLL 中,则您可以使用反射检查此程序集的内容。这包括使用静态反射 API 函数Assembly::Load来加载程序集。此函数返回Assembly对象的地址,然后它可以在该对象中查询关于模块和类型的信息。

反射系统一旦成功加载程序集,即会用Assembly::GetTypes函数检索“Type”对象的数组。每个数组元素都包含关于不同类型的信息(虽然本例中只定义了一个类)。通过循环,将使用Type::GetMembers函数对此数组中的每个“Type”查询关于类型成员的信息。此函数返回一个MethodInfo对象的数组,每个对象都包含关于类型中成员函数、数据成员或属性的信息。

请注意,方法列表包含在TestClass中显式定义的函数以及从System::Object类隐式继承的函数。在用 .NET(而不是用 Visual C++ 语法)进行描述时,属性将显示为由 get/set 函数访问的基础数据成员。get/set 函数在此列表中显示为规则方法。整个公共语言运行库都支持反射,但 Visual C++ 编译器不支持反射。

虽然您使用此代码来检查已定义的程序集,但也可以使用此代码来检查 .NET 程序集。例如,如果将 TestAssembly 更改为 mscorlib,则将看到在 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<Type^>^ 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<MemberInfo^>^ 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);
}

相关文章:

  • wkwebview 会缓存html,ios – 设备上的WKWebView无法加载缓存的HTML
  • 用计算机语言拜年,鸡年大吉!22种编程语言大拜年
  • 计算机专业英语教学重难点,浅析计算机专业英语的教学现状及对策
  • 博客PV突破300万暨两次线上活动圆满结束
  • vue html5播放流媒体,关于视频播放器:H5播放Rtmp之vuevideoplayer播放播放
  • protected,internal和protected internal
  • 推荐信计算机专业模板,计算机专业留学推荐信模板
  • 自己动手搭建WAMP
  • win7远程管理html,教你怎样win7远程桌面连接设置
  • 一劳永逸的修改Maven的编译级别
  • 怎样用计算机表白我爱你,高级表白密码,教你如何用数字表达出我爱你
  • 嵌入式linux上QT标准键盘输入的实现
  • 东北大学计算机应用基础试题,东北大学网络教育本科14秋学期《计算机应用基础》在线作业1试题答案...
  • 面试别人实际是在考验自己
  • 项目管理计算机考试试题,计算机软件项目管理考试试题及答案.doc
  • create-react-app项目添加less配置
  • Cumulo 的 ClojureScript 模块已经成型
  • Elasticsearch 参考指南(升级前重新索引)
  • node.js
  • oldjun 检测网站的经验
  • Python3爬取英雄联盟英雄皮肤大图
  • Redis 懒删除(lazy free)简史
  • Three.js 再探 - 写一个跳一跳极简版游戏
  • vue中实现单选
  • 猫头鹰的深夜翻译:JDK9 NotNullOrElse方法
  • 区块链共识机制优缺点对比都是什么
  • 入手阿里云新服务器的部署NODE
  • 突破自己的技术思维
  • 以太坊客户端Geth命令参数详解
  • 资深实践篇 | 基于Kubernetes 1.61的Kubernetes Scheduler 调度详解 ...
  • ​一帧图像的Android之旅 :应用的首个绘制请求
  • #LLM入门|Prompt#1.8_聊天机器人_Chatbot
  • #ubuntu# #git# repository git config --global --add safe.directory
  • $GOPATH/go.mod exists but should not goland
  • (cos^2 X)的定积分,求积分 ∫sin^2(x) dx
  • (八)Spring源码解析:Spring MVC
  • (附源码)计算机毕业设计SSM疫情社区管理系统
  • (转)C#开发微信门户及应用(1)--开始使用微信接口
  • ****** 二十三 ******、软设笔记【数据库】-数据操作-常用关系操作、关系运算
  • .NET Standard / dotnet-core / net472 —— .NET 究竟应该如何大小写?
  • .NET 设计一套高性能的弱事件机制
  • .net中生成excel后调整宽度
  • /usr/bin/perl:bad interpreter:No such file or directory 的解决办法
  • ::什么意思
  • []error LNK2001: unresolved external symbol _m
  • [2015][note]基于薄向列液晶层的可调谐THz fishnet超材料快速开关——
  • [20170705]lsnrctl status LISTENER_SCAN1
  • [C#] 基于 yield 语句的迭代器逻辑懒执行
  • [C#][DevPress]事件委托的使用
  • [C#基础知识系列]专题十七:深入理解动态类型
  • [C/C++随笔] char与unsigned char区别
  • [Electron]ipcMain.on和ipcMain.handle的区别
  • [GDMEC-无人机遥感研究小组]无人机遥感小组-000-数据集制备
  • [GDOUCTF 2023]<ez_ze> SSTI 过滤数字 大括号{等
  • [Java] IDEA Scala环境搭建