微软官方教程:https://docs.microsoft.com/zh-cn/dotnet/framework/reflection-and-codedom/viewing-type-information

元編程(英語:Metaprogramming),又譯超編程,是指某类计算机程序的编写,这类计算机程序编写或者操纵其它程序(或者自身)作为它们的資料,或者在运行时完成部分本应在编译时完成的工作。多数情况下,与手工编写全部代码相比,程序员可以获得更高的工作效率,或者给与程序更大的灵活度去处理新的情形而无需重新编译。

编写元程序的语言称之为元语言。被操纵的程序的语言称之为「目标语言」。一门编程语言同时也是自身的元语言的能力称之为「反射」或者「自反」。

反射是促进元编程的一种很有价值的语言特性。把编程语言自身作为一級資料類型(如LISPForthRebol)也很有用。支持泛型编程的语言也使用元编程能力。

元编程通常通过两种方式实现。一种是通过应用程序编程接口(APIs)将运行时引擎的内部信息暴露于编程代码。另一种是动态执行包含编程命令的字符串表达式。因此,“程序能够编写程序”。虽然两种方式都能用于同一种语言,但大多数语言趋向于偏向其中一种。

个人理解元编程

C# 目前的反射只能对现在类型进行操作,还不能创建新的类型或编辑现有字段的类型信息。
反射获取的字段、属性、方法 如一个万能钥匙,可以用它操控所有的类型实例。C#泛型 反射都是元编程的能力

什么是反射

在程序运行时,动态获取 程序集, 类型(class,interface)和类型的成员信息(方法,字段,属性等)。
在程序运行时,动态创建 类型实例, 以及调用和方法 动态创建出来的 类型实例的成员。net core 一个程序运行起来以后,有一个AppDomain,在这个AppDomain中放了我们用到的所有assembly。

反射机制对应设计模式中的策略模式。

反射的作用:
1. 可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现 有对象中获取类型
2. 应用程序需要在运行时从某个特定的程序集中载入一个特定的类型,以便实现某个任务时可以用到反射。
3. 反射主要应用与类库,这些类库需要知道一个类型的定义,以便提供更多的功能。框架(Spring .net/ .Net MVC等)

4、破坏单例模式 反射可以突破访问限制,直接调用私有构造函数

5、依赖注入

6、插件编程

7、序列化

C#反射的局限

反射不能修改readonly、只读属性、const字段、字符串拘留池  。

当修改readonly字段时候出现异常 System.FieldAccessException:“Cannot set initonly static field 'data' after type 'Program1' is initialized.”

修改只读属性的时候出现:Setting static readonly properties fails 异常。

using System.Reflection;

mod();

static void mod()
{
Program1 ss = new();
var fieldInfo = typeof(Program1).GetField("data", BindingFlags.Static | BindingFlags.NonPublic);
// fieldInfo.SetValue(ss, "MOD"); fieldInfo.SetValue(ss, "MOD");//出现异常 System.FieldAccessException:“Cannot set initonly static field 'data' after type 'Program1' is initialized.”
}
class Program1
{
static readonly string data = "df";
//
//这句运行正常 static string data = "df"; }

反射在在设计模式实现中的使用

  采用反射技术可以简化工厂的实现。 

  (1)工厂方法:通过反射可以将需要实现的子类名称传递给工厂方法,这样无须在子类中实现类的实例化。 

  (2)抽象工厂:使用反射可以减少抽象工厂的子类。 

  采用反射技术可以简化工厂代码的复杂程度,在.NET项目中,采用反射技术的工厂已经基本代替了工厂方法。 

  采用反射技术可以极大地简化对象的生成,对以下设计模式的实现也有很大影响。 

  (1)命令模式:可以采用命令的类型名称作为参数直接获得命令的实例,并且可以动态执行命令。 

  (2)享元模式:采用反射技术实例化享元可以简化享元工厂

反射用到命名空间

System.Reflection
    
System.Type
   
System.Reflection.Assembly
System.Reflection.Emit

System.Type 类:通过这个类可以访问任何给定数据类型的信息。
对于反射起着核心的作用。但它是一个抽象的基类,Type有与每种数据类型对应的派生类,我们使用这个派生类的对象的方法、字段、属性来查找有关该类型的所有信息。


System.Reflection.Assembly类:它可以用于访问给定程序集的信息,或者把这个程序集加载到程序中。

System.Reflection.Emit命名空间的类提供了一种特殊形式的反射,可以在运行时构造类型。

System.Reflection


MemberInfo 包含以下类型:

MemberTypes

 [Flags]
public enum MemberTypes
{
Constructor = 1,
Event = 2,
Field = 4,
Method = 8,
Property = 16,
TypeInfo = 32,
Custom = 64,
NestedType = 128,
All = 191
}
}

TypeInfo和Type的区别与选择

Type 类:表示类型声明(类型的引用):类类型、接口类型、数组类型、值类型、枚举类型、类型参数、泛型类型定义,以及开放或封闭构造的泛型类型。。
TypeInfo 类:表示类类型、接口类型、数组类型、值类型、枚举类型、类型参数、泛型类型定义,以及开放或封闭构造的泛型类型的类型声明。

TypeInfo对象表示类型定义本身,而 Type 对象表示对类型定义的引用。 获取 TypeInfo 对象将强制加载包含该类型的程序集。 相比之下,你可以操作 Type 对象,而无需运行时加载它们引用的程序集。

TypeInfo出现于.net framework 4.5之后,这次调整用于区分两个概念:“reference”和“definition”。
    reference is a shallow representation of something
    definition is  a rich representation of something
例如System.Reflection.Assembly就代表了一个“definition” ,而System.Reflection.AssemblyName就代表了一个“reference”
在未区分这两种概念之前,System.Type是这两种概念的混合,通过一个Type实例,既可以获得该类型的“Name、Assembly、……”,也可以获得该类型的“NestTypes、Fields、Properties、Methods、Constructors、Events……”。这也导致了当我们获得一个Type的时候,就把它全部的信息都加载到了内存中,但是很多情况下,这并不是我们想要看到的。举例如下:
更多相关内容请查看:https://blog.csdn.net/fengsocool/article/details/85927995

public MyClass:BaseClass{

}

//获得MyClass的类型对象

Type t=MyClass.GetType();

在.net framework 4中,获得类型对象时,同时获得了基类(BaseClass)的类型对象,同时包括基类对象的“reference”和“definition”,因此需要把基类所在的程序集也加载进来。
在.net framework 4.5中,如下代码:
Type baseType = MyClass.GetType().GetTypeInfo().BaseType;
 在获得类型对象时,只获得了基类的"reference"

反射经常用方法

#define DEBUG  ////C# 的宏定义必须出现在所有代码之,告诉编译器哪些特性要编译IL代码
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection; namespace TestReflection
{
public delegate void NoParametMethodEventHandler(object o, EventArgs e);
public delegate void methodBing(string x); public class UnFinsedAttribute:Attribute
{ }
public interface IPlay { void Play(); }
[UnFinsed]
class MyType:IPlay
{ public event NoParametMethodEventHandler DianMing=delegate { };
Int32 myField;
//构造函数
public MyType()
{ }
public MyType(ref Int32 x) { x *= 5; }
public MyType(int x) { x = 5; }
public MyType(Int32 x, int c) { x *= 5; }
public MyType(Int32[] x, int c) { c *= 5; }
public override String ToString()=>myField.ToString();
public void Pritn(string x) => Console.WriteLine("Pritn(string x)");
public void Pritn(string x,int s) => Console.WriteLine("Pritn(string x,int s)");
//属性
public Int32 MyProp
{
get { return myField; }
set
{
if (value < 1)
throw new ArgumentOutOfRangeException("value", value, "value must be > 0");
myField = value;
}
} public string Address { get; set; }
public string Name => "自定义类"; //索引 public int this[string i]
{
get { return 1; }
set { }
}
public int this[int i]
{
get { return 1; }
set { }
}
//事件触发器
public void ClickMe()
{
DianMing += Huida;
DianMing.Invoke(new object(),new EventArgs());
}
//事件处理器
public void Huida(object o, EventArgs e)
{
Console.WriteLine($"{Name}到");
} public void Play()
{
Console.WriteLine("接口方法");
}
public void BingMethodToDelegat(string x)
{
Console.WriteLine($"你调用了动态方法BingMethodToDelegat方法的参数x:{x} 该方法调用了实例属性MyProp:{MyProp}");
}
public static void StaticMethod(string x)
{ Console.WriteLine("你调用了静态方法StaticMethod");
}
} class MyApp
{
static void Main()
{ Type type = typeof(MyType);
Type parameterType = typeof(int);
//====================构造函数获取 // Create an instance of a type. Object[] args = new Object[] { 8 };
object obj = Activator.CreateInstance(type);
//创建实例
Console.WriteLine("=========创建实例===============");
//创建泛型
Type open = typeof(Dictionary<,>);//创建泛型类型的实例,首先要获取对应的开放类型(Open type)的引用,然后调用Type类型的MakeGenericType方法
//传入一个包含泛型参数的数组即可获取一个封闭类型(Closed Type).使用该封闭类型,调用Activator接受Type参数的某个方法既可以构造出具体的实例。
Type closeType = open.MakeGenericType(typeof(String), typeof(object)); object obj1 = Activator.CreateInstance(closeType);//方法一、Activator创建实例
ConstructorInfo constructorCreature = type.GetConstructor(Array.Empty<Type>());
ConstructorInfo constructor6 = type.GetConstructor(new[] { typeof(int) });
var obj2 = constructor6.Invoke(new[]{(Object)3});//方法二、构造创建实例
Object obj3= type.Assembly.CreateInstance("MyType");//方法三、Assembly创建实例
Object obj4 = type.InvokeMember(null, BindingFlags.CreateInstance, null, null, new Object[] { 8 });//方法四、InvokeMember 创建实例 Type refParameter = parameterType.MakeByRefType(); //参数 MyType(ref Int32 x);
Type arrayParameter = parameterType.MakeArrayType(2); //参数数组int[]= new int[2];
Type parameterGeneric = typeof(List<>);//泛型参数
Type parameterGeneric2 = parameterGeneric.MakeGenericType(typeof(int));//list<int> //获取字段
Console.WriteLine("=========获取字段===============");
FieldInfo field = type.GetField("myField",BindingFlags.NonPublic|BindingFlags.Instance);
field.SetValue(obj, 1);//设置私有字段的
Console.WriteLine(field.GetValue(obj));//获取私有字段
Console.WriteLine(field.FieldType);//获取字段类型 //获取构造函数
Console.WriteLine("=========获取构造函数 ===========");
ConstructorInfo constructorInfo1 = type.GetConstructor(new Type[0]);//过时 获取无参构造函数 参数是无 new Type[0] 表示空数组
ConstructorInfo constructorInfo2 = type.GetConstructor(Array.Empty<Type>());//获取无参构造函数 参数是无 new Type[0] 表示空数组
ConstructorInfo constructorInfo3 = type.GetConstructor(new Type[] { });// 过时 获取无参构造函数 参数是无(new Type[] { }]表示空数组
ConstructorInfo constructorInfo4 = type.GetConstructor(Type.EmptyTypes); //获取无参构造函数 这个才是最正确符合逻辑的写法
ConstructorInfo constructorInfo5 = type.GetConstructor(new[] { refParameter });//MyType(ref Int32 x)
ConstructorInfo constructorInfo6 = type.GetConstructor(new[] { typeof(int) });//MyType(Int32 x)
ConstructorInfo constructorInfo7 = type.GetConstructor(new[] { typeof(int), typeof(int) });//MyType(Int32 x,int c)
ConstructorInfo constructorInfo8 = type.GetConstructor(new[] { typeof(int[]), typeof(int) });//MyType(Int32 x)
ConstructorInfo[] constructorInfoAll = type.GetConstructors();//获取所有构造函数 //获取属性
Console.WriteLine("========获取属性===============");
PropertyInfo propertyInfo1 = type.GetProperty("Name");
PropertyInfo propertyInfo2 = type.GetProperty("Address");
PropertyInfo[] propertyInfoAll = type.GetProperties();//获取所有的属性,把索引也获取进去了 索引是有参属性,名字item
Console.WriteLine(propertyInfo2.PropertyType);//属性的类型 Console.WriteLine(propertyInfo1.GetValue(obj));
// propertyInfo1.SetValue(obj, "haha");//错误的,因为没有set属性,所以无法设置,set就是set函数
Console.WriteLine(propertyInfo1.GetValue(obj)); Console.WriteLine(propertyInfo2.GetValue(obj));
propertyInfo2.SetValue(obj, "haha");//正确的,因为有set属性。
Console.WriteLine(propertyInfo2.GetValue(obj)); //获取索引
Console.WriteLine("=========获取索引===============");
PropertyInfo propertyInfo3 = type.GetProperty("Item",typeof(int),new[] { typeof(int) });//获取索引,索引的名字都是Item发,获取返回值是int,参数是int的属性。 //获取调用方法
Console.WriteLine("=========获取调用方法============");
MethodInfo method1 = type.GetMethod("ToString");
MethodInfo method2 = type.GetMethod("Pritn",new[] { typeof(string) });//获取一个参数的方法
MethodInfo method3 = type.GetMethod("Pritn",new[] {typeof(string),typeof(int)});//获取2个参数的方法
MethodInfo method4 = type.GetMethod("ClickMe");
MethodInfo method5 = type.GetMethod("Huida",new[] { typeof(object), typeof(EventArgs) });
MethodInfo method6 = type.GetMethod("StaticMethod", new[] { typeof(string) });//获取一个参数的方法 MemberInfo[] methodAll = type.GetMethods();
method4.Invoke(obj, null);//执行方法 //事件
Console.WriteLine("=========事件===============");
NoParametMethodEventHandler de = Huida2 ;
EventInfo @event = type.GetEvent("DianMing");//
@event.AddEventHandler(obj, de);//订阅事件
void Huida2(object o, EventArgs e) //处理器
{
Console.WriteLine("manin到");
}
method4.Invoke(obj, null);//执行方法
Console.WriteLine(@event.EventHandlerType.Name);//事件类型 //接口
Console.WriteLine("=========接口===============");
Type interFace = type.GetInterface("IPlay"); //委托绑定
Console.WriteLine("=========委托绑定===============");
Delegate methodDelegat1 = Delegate.CreateDelegate(typeof(methodBing), obj, "BingMethodToDelegat");//调用实例方法,必须绑定实例
methodDelegat1.DynamicInvoke("methodDelegat1");//实例方法要绑定实例使用,要不很容易报错,因为方法内部会调用很多内部成员 Delegate methodDelegat2 = Delegate.CreateDelegate(typeof(methodBing), null, method6);//调用了静态方法,静态不依附实例
methodDelegat2.DynamicInvoke("methodDelegat2"); //获取特性
var typeAttribute= type.GetCustomAttribute(typeof(UnFinsedAttribute)); } } }

反射为什么慢?

使用反射来调用类型或者触发方法,或者访问一个字段或者属性时clr 需要做更多的工作:校验参数,检查权限等等,所以速度是非常慢的。

【C#反射】开篇的更多相关文章

  1. 一年之计在于春,2015开篇:PDF.NET SOD Ver 5.1完全开源

    前言: 自从我2014年下半年到现在的某电商公司工作后,工作太忙,一直没有写过一篇博客,甚至连14年股票市场的牛市都错过了,现在马上要过年了,而今天又是立春节气,如果再不动手,那么明年这个无春的年,也 ...

  2. [.net 面向对象程序设计进阶] (1) 开篇

    [.net 面向对象程序设计进阶] (1) 开篇 上一系列文章<.net 面向对象编程基础>写完后,很多小伙伴们希望我有时间再写一点进阶的文章,于是有了这个系列文章.这一系列的文章中, 对 ...

  3. 《InsideUE4》UObject(一)开篇

    UE生UObject,UObject生万物 引言 在上个GamePlay专题,谈到UE创建游戏世界的时候(GamePlay架构(一)Actor和Component),简单的介绍了一下UObject的功 ...

  4. .NET面试题解析(00)-开篇来谈谈面试 & 系列文章索引

    系列文章索引: .NET面试题解析(01)-值类型与引用类型 .NET面试题解析(02)-拆箱与装箱 .NET面试题解析(03)-string与字符操作 .NET面试题解析(04)-类型.方法与继承 ...

  5. 程序猿修仙之路--数据结构之你是否真的懂数组? c#socket TCP同步网络通信 用lambda表达式树替代反射 ASP.NET MVC如何做一个简单的非法登录拦截

    程序猿修仙之路--数据结构之你是否真的懂数组?   数据结构 但凡IT江湖侠士,算法与数据结构为必修之课.早有前辈已经明确指出:程序=算法+数据结构  .要想在之后的江湖历练中通关,数据结构必不可少. ...

  6. java 反射和泛型

    反射 在计算机科学中,反射是指计算机程序在运行时(Run time)可以访问.检测和修改它本身状态或行为的一种能力.[1]用比喻来说,反射就是程序在运行的时候能够“观察”并且修改自己的行为. 要注意术 ...

  7. 【Spring实战】----开篇(包含系列目录链接)

    [Spring实战]----开篇(包含系列目录链接) 置顶2016年11月10日 11:12:56 阅读数:3617 终于还是要对Spring进行解剖,接下来Spring实战篇系列会以应用了Sprin ...

  8. .netCore 反射 :Could not load file or assembly 系统找不到指定文件

    “System.IO.FileNotFoundException:“Could not load file or assembly 'ClassLibrary2, Culture=neutral, P ...

  9. 一个三年Android开发的总结-开篇

    一个三年Android开发的总结-开篇 转眼间全职从事Android开发已有三年,想把这一阶段的积累总结记录并展现出来,作为Android开发必备的知识,希望对有一定Android开发基础的人进阶有裨 ...

随机推荐

  1. golang中bufio和ioutil的使用

    bufio bufio包实现了带缓冲区的读写,是对文件读写的封装 bufio缓冲写数据 模式 含义 os.O_WRONLY 只写 os.O_CREATE 创建文件 os.O_RDONLY 只读 os. ...

  2. IDEA包名分层问题

    解决办法: 将默认的"Hide empty Middle Packages"或者"compact middle packages"勾选项去掉,这样就不会把中间空 ...

  3. centos下python2升级为python3

    1.下载 下载地址 https://www.python.org/downloads/release/python-353/ 选择"Gzipped source tarball"这 ...

  4. html图像 表格 列表

    创建图像映射 <img src="/demo/planets.gif" width="145" height="126" alt=&q ...

  5. MongoDB常用运维命令

    # 查看Mongodb版本信息 mongos> db.version() # 关闭mongodb服务 mongos> use admin mongos> shutdownServer ...

  6. kubernetes之node 宕机,pod驱离问题解决

    背景: 当node宕机时,希望该node节点上的pod能够快速疏散到其他节点,并提供服务.测试发现,要等待5分钟,上面的pod才会疏散. 网上介绍通过修改 /etc/kubernetes/manife ...

  7. pytorch运行错误:ValueError: too many dimensions 'str'

    问题: 本人在使用BERT进行微调的时候,在读取数据的时候出现了一个错误:ValueError: too many dimensions 'str'    于是我Debug了以后,发现问题出现在这个部 ...

  8. ApacheCN Angular 译文集 20211114 更新

    Angular 专家级编程 零.前言 一.架构概述和在 Angular 中构建简单应用 二.将 AngularJS 应用迁移到 Angular 应用 三.使用 Angular CLI 生成具有最佳实践 ...

  9. 精通 TensorFlow 1.x·翻译完成

    原文:Mastering TensorFlow 1.x 协议:CC BY-NC-SA 4.0 不要担心自己的形象,只关心如何实现目标.--<原则>,生活原则 2.3.c 在线阅读 Apac ...

  10. PriorityQueue的用法和底层实现原理

    定义 PriorityQueue类在Java1.5中引入并作为 Java Collections Framework 的一部分.PriorityQueue是基于优先堆的一个无界队列,这个优先队列中的元 ...