不拘小节的作业本 · Remove spaces from ...· 1 年前 · |
正直的人字拖 · Rust应用调用C语言动态库_rust ...· 1 年前 · |
行走的弓箭 · SQLserver中用convert函数转换 ...· 1 年前 · |
在上一章中,我们探究了 C# 引入程序集的各种方法,这一章节笔者将探究 C# 中使用反射的各种操作和代码实践。
目录
《C# 7.0 本质论》中:
反射 是指对程序集中的元数据进行检查的过程。
《C# 7.0 核心技术指南》中:
在运行时检查并使用元数据和编译代码的操作称为 反射 。
Microsoft Docs :
反射提供描述程序集、模块和类型的对象。 可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型,然后调用其方法或访问其字段和属性。
《C# 7.0 本质论》、《C# 7.0 核心技术指南》、《Microsoft Docs》中,关于反射的作用,提纲整理如下:
System.Type
表示类型声明:类类型、接口类型、数组类型、值类型、枚举类型、类型参数、泛型类型定义,以及开放或封闭构造的泛型类型。
Type 类型是反射技术的基础,反射所有操作都离不开 Type。
C# 中,一个类型,可有以下元素组成:
类型名、构造函数/参数、方法/方法参数、字段、属性、基类型、继承接口等。
而我们使用反射技术时,一般关注以下的信息:
Type type = typeof(Program);
Console.WriteLine(type.Namespace);
Console.WriteLine(type.Name); // 类型名称
Console.WriteLine(type.FullName); // 类型的完全限定名
Assembly ass = type.Assembly;
Console.WriteLine(ass.FullName);
输出:
Mytest
Program
Mytest.Program
ConsoleApp4, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
下面,笔者将慢慢探究 C# 中关于 反射 的内容以及实践验证。
获取 Type 主要有两种方法:
Type type1 = typeof(MyClass);
MyClass myClass = new MyClass();
Type type2 = myClass.GetType();
typeof()
静态方法,可以直接获取一个类型的 Type;
.GetType()
则是获取一个实例的类型;
两种方法想必各位以及司空见惯~
反射一般是编写代码时,很多情况不能明确下才使用,一般结合程序集来获取;
Assembly ass = Assembly.LoadFrom(@"C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\3.0.0\ref\netcoreapp3.0\System.Console.dll");
// 获取当前控制台程序的程序集,并且获取 Console 这个类型
// 注意,要使用完全限定名
Type type = ass.GetType("System.Console");
Type[] types = ass.GetTypes();
Console.WriteLine("type: " + type.Name);
// 获取 System.Console.dll 中的所有类型
foreach (var item in types)
Console.WriteLine("item: " + item.Name);
Console.ReadKey();
关于完全限定名,要根据实际情况填写。
获取数组的 Type ,这里有两种情况,一种是将类型生成类型的数组,另一种是本身就是数组类型;
例如说,
本身是 int 类型, 生成 int[] 数组的 Type 类型;
本身是 int[] 类型,生成 int[] 数组的 Type 类型;
前者通过实例的
MakeArrayType()
方法生成,示例如下
// int 生成 int[]
Type typeArray_A = typeof(int).MakeArrayType();
// int 生成 int[,] 多维数组
Type typeArray_B = typeof(int).MakeArrayType(2);
Console.WriteLine(typeArray_A.Name);
Console.WriteLine(typeArray_B.Name);
Console.ReadKey();
输出
Int32[]
Int32[,]
如果是交错数组
[][]
呢。。。怎么创建。。。别急。。。后面有。。。
如果一个类型本身就是数组呢?
Type type = typeof(int[]);
Console.WriteLine(type);
不需要进行任何操作。。。
假如有个数组
int[]
,我们要获取数组的元素类型 int,可以使用
Type type = typeof(int[]);
Type type1 = type.GetElementType();
Console.WriteLine(type1.Name);
获取一个多维数组有维数
Type type = typeof(int[,,,,,,,,,,]);
Console.WriteLine(type.GetArrayRank());
输出:11
Type type = typeof(int[][][][][]);
Console.WriteLine(type.GetArrayRank());
输出:1
int[,]
这样的,称为多维数组;
而
int[][]
这样的,称为矩形数组、交错数组、锯齿数组(称呼有点多)。
关于这方面的知识,可以参考笔者的另一篇文章: https://www.cnblogs.com/whuanle/p/9936047.html
Type 中,没有创建交错数组的方式,因为实际上,交错数组是 数组的数组,例如
(int[])
的数组。
// 先获取一个类型
Type arrayType = typeof(int[]);
Type _Array = arrayType.MakeArrayType();
Console.WriteLine(_Array.Name);
输出
Int32[][]
嵌套类型的使用跟正常的类型一致,嵌套类型的完全限定名称由
{类型}+{嵌套类型}
组成,其它地方没有什么差异。
在 Program 创建一个类
MyClass
。
Type type = typeof(Program.MyClass);
Console.WriteLine(type.Namespace);
Console.WriteLine(type.Name);
Console.WriteLine(type.FullName);
Assembly ass = type.Assembly;
Console.WriteLine(ass.FullName);
输出:
Mytest
MyClass
Mytest.Program+MyClass
ConsoleApp4, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
完全限定名称:
Mytest.Program+MyClass
,由加号
+
连接。
先看以下例子
Type typeA = typeof(Dictionary<,>);
Type typeB = typeof(Dictionary<string, int>);
Type typeC = typeof(List<>);
Type typeD = typeof(List<string>);
然后打印
Name
Console.WriteLine(typeA.Name);
Console.WriteLine(typeB.Name);
Console.WriteLine(typeC.Name);
Console.WriteLine(typeD.Name);
输出
Dictionary`2
Dictionary`2
List`1
List`1
打印
FullName
Console.WriteLine(typeA.FullName);
Console.WriteLine(typeB.FullName);
Console.WriteLine(typeC.FullName);
Console.WriteLine(typeD.FullName);
输出
System.Collections.Generic.Dictionary`2
System.Collections.Generic.Dictionary`2[[System.String, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Int32, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]
System.Collections.Generic.List`1
System.Collections.Generic.List`1[[System.String, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]
Dictionary
2 ,这个 `后表示此泛型类型有多少个泛型参数。
使用
.Name
看不出参数以及参数类型;
FullName
可以看到完整的参数。
Type 中,与 泛型 有关的函数如下:
System.Type 成员名称 |
说明 |
---|---|
IsGenericType |
如果类型是泛型,则返回 true。 |
GetGenericArguments() |
返回 Type 对象的数组,这些对象表示为构造类型提供的类型实参或泛型类型定义的类型形参。 |
GetGenericTypeDefinition() |
返回当前构造类型的基础泛型类型定义。 |
GetGenericParameterConstraints() |
返回表示当前泛型类型参数约束的 Type 对象的数组。 |
ContainsGenericParameters() |
如果类型或任何其封闭类型或方法包含未提供特定类型的类型参数,则返回 true。 |
GenericParameterAttributes() |
获取描述当前泛型类型参数的特殊约束的 GenericParameterAttributes 标志组合。 |
GenericParameterPosition() |
对于表示类型参数的 Type 对象,获取类型参数在声明其类型参数的泛型类型定义或泛型方法定义的类型参数列表中的位置。 |
IsGenericParameter |
获取一个值,该值指示当前 Type 是否表示泛型类型或方法定义中的类型参数。 |
IsGenericTypeDefinition |
获取一个值,该值指示当前 Type 是否表示可以用来构造其他泛型类型的泛型类型定义。 如果该类型表示泛型类型的定义,则返回 true。 |
DeclaringMethod() |
返回定义当前泛型类型参数的泛型方法,如果类型参数未由泛型方法定义,则返回 null。 |
MakeGenericType() |
替代由当前泛型类型定义的类型参数组成的类型数组的元素,并返回表示结果构造类型的 Type 对象。 |
Type typeA = typeof(Dictionary<,>);
Type typeB = typeof(Dictionary<string, int>);
Console.WriteLine(typeA.IsGenericMethodParameter +"|"+typeB.IsGenericMethodParameter);
Console.WriteLine(typeA.IsGenericParameter + "|" + typeB.IsGenericParameter);
Console.WriteLine(typeA.IsGenericType + "|" + typeB.IsGenericType);
Console.WriteLine(typeA.IsGenericTypeDefinition + "|" + typeB.IsGenericTypeDefinition);
Console.WriteLine(typeA.IsGenericTypeParameter + "|" + typeB.IsGenericTypeParameter);
输出:
False|False
False|False
True|True
True|False
False|False
老实说,除了
IsGenericType
,其它的我都不懂什么意思。
GetGenericArguments()
可以获取泛型的参数类型;
Type type = typeof(Dictionary<string, int>);
Type[] list = type.GetGenericArguments();
foreach (var item in list)
Console.WriteLine(item.Name);
输出
String
Int32
创建一个类型
public class MyClass
public void Test(string str, ref string a, out string b)
b = "666";
Console.WriteLine(b);
}
获取方法的参数列表
// 获取一个方法的参数列表
ParameterInfo[] paramList = typeof(MyClass).GetMethod(nameof(MyClass.Test)).GetParameters();
foreach (var item in paramList)
Console.WriteLine(item);
输出:
System.String str
System.String& a