前期绑定与后期绑定 在.NET中,前期绑定(Early Binding)是指在编译时就确定了对象的类型和方法,而后期绑定(Late Binding)或动态绑定是在运行时确定对象的类型和方法。
前置知识:C#类型系统结构 C#作为C++++ ,在类型系统上沿用C++的类型系统
前期绑定 在代码能执行之前,将代码中依赖的assembly,module,class,method,field等类型系统 的元素提前构建好。
比如一个简单的的控制台,就自动提前加载了各种需要的DLL文件。完成前期绑定。
后期绑定 后期绑定的优点是可以在运行时更改类型,无需重新编译代码。缺点是在编译时不进行类型检查,可能导致运行时错误。dynamic ,多态,System.Reflection 等
举个例子,使用Reflection下的“元数据查询API”,动态加载DLL
            var  dllpath  =  "xxx.dll" ;
            Assembly  assembly  =  Assembly.LoadFrom(dllpath);
            Type  dataAccessType  =  assembly.GetType("xxxxx" );
            object  dataAccess  =  Activator.CreateInstance(dataAccessType);
            MethodInfo  addMethod  =  dataAccessType.GetMethod("Add" );
			
            addMethod.Invoke(dataAccess, new  object [] { "hello world"  });
反射 反射的本质就是“操作元数据” 
什么是元数据? MetaData,本是上就是存储在dll中的一个信息数据库,记录了这个assembled中有哪些方法,哪些类,哪些属性等等信息
举个例子:
通过Reflection XXXInfo系列API 查询所有细节
Type t = typeof (System.IO.FileStream);
FieldInfo[] fi = t.GetFields(BindingFlags.Static  | BindingFlags.NonPublic | BindingFlags.Public );
PropertyInfo[] pi = t.GetProperties(BindingFlags.Static  | BindingFlags.NonPublic | BindingFlags.Public );
EventInfo[] ei = t.GetEvents(BindingFlags.Static  | BindingFlags.NonPublic | BindingFlags.Public );
......
反射如何构建类型系统 通过Reflection XXXBuilder系列API 构建一个全新的类型
            AssemblyBuilder  ab  =  AssemblyBuilder.DefineDynamicAssembly(new  AssemblyName ("MyAssembly" ), AssemblyBuilderAccess.RunAndCollect);
            ModuleBuilder  mob  =  ab.DefineDynamicModule("MyModule" );
            TypeBuilder  tb  =  mob.DefineType("MyType" , TypeAttributes.Public | TypeAttributes.Class);
            MethodBuilder  mb  =  tb.DefineMethod("SumMethod" , MethodAttributes.Public | MethodAttributes.Static, typeof(int ), new  Type [] { typeof(int ), typeof(int ) });
            ILGenerator  il  =  mb.GetILGenerator();
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldarg_1);
            il.Emit(OpCodes.Add);
            il.Emit(OpCodes.Ret);
            Type  type  =  tb.CreateType();  
            MethodInfo  method  =  type.GetMethod("SumMethod" );
            Console.WriteLine(method.Invoke(null , new  object [] { 5 , 10  }));
反射底层调用 C#的类型系统,与C++的类型系统是一一对应的。因此其底层必定是调用C++的方法。
眼见为实,以Invoke为例 
反射到底慢在哪? 动态解析 动态调用 无法在编译时优化 额外的安全检查 缓存易失效 总之,千言万语汇成一句话。最好的反射就是不要用反射。除非你能保证对性能要求不高/缓存高命中率 
CLR的对反射的优化 除了缓存反射的汇编,.NET 中提供了一系列新特性来尽可能的绕开“反射”
Emit Emit 是 .NET 提供的一种动态生成和编译代码的技术。通过 Emit,我们可以动态生成一个新的方法,这个方法可以直接访问私有成员,这对于一些特殊场景非常有用,比如动态代理、代码生成器、AOP(面向切面编程)等.
public  class  Person 
{
    private  int  _age;
    public  override  string  ToString ()return  _age.ToString();
    }
}
static  void  EmitTest (Person person )typeof (Person);
    
    FieldInfo ageField = personType.GetField("_age" , BindingFlags.Instance | BindingFlags.NonPublic);
    if  (ageField == null )
    {
        throw  new  ArgumentException("未找到指定的私有字段" );
    }
    
    DynamicMethod dynamicMethod = new  DynamicMethod("SetAgeValue" , null , new  Type[] { typeof (Person), typeof (int ) }, personType);
    
    ILGenerator ilGenerator = dynamicMethod.GetILGenerator();
    
    ilGenerator.Emit(OpCodes.Ldarg_0);
    
    ilGenerator.Emit(OpCodes.Ldarg_1);
    
    ilGenerator.Emit(OpCodes.Stfld, ageField);
    
    ilGenerator.Emit(OpCodes.Ret);
    
    Action<Person, int > setAgeAction = (Action<Person, int >)dynamicMethod.CreateDelegate(typeof (Action<Person, int >));
    
    setAgeAction(person, 100 );
}
切构建代码又臭又长。
Expression Expression 是 .NET 提供的一种表达式树的技术。通过 Expression,我们可以创建一个表达式树,然后编译这个表达式树,生成一个可以访问私有成员的方法
static  void  ExpressionTest (Person person) 
{
    
    Type  personType  =  typeof(Person);
    
    FieldInfo  ageField  =  personType.GetField("_age" , BindingFlags.Instance | BindingFlags.NonPublic);
    if  (ageField == null )
    {
        throw  new  ArgumentException ("未找到指定的私有字段" );
    }
    
    ParameterExpression  instanceParam  =  Expression.Parameter(personType, "instance" );
    
    ParameterExpression  newValueParam  =  Expression.Parameter(typeof(int ), "newValue" );
    
    BinaryExpression  assignExpression  =  Expression.Assign(Expression.Field(instanceParam, ageField), newValueParam);
    
    BlockExpression  blockExpression  =  Expression.Block(assignExpression);
    
    Action<Person, int > setAgeAction = Expression.Lambda<Action<Person, int >>(blockExpression, instanceParam, newValueParam).Compile();
    
    setAgeAction(person, 100 );
}
切构建代码又臭又长。
UnsafeAccessorAttribute .Net 8中引入了新特性UnsafeAccessorAttribute  。
static  void  New ()var  person = new  Person();
    GetAgeField(person) = 100 ;
}
[UnsafeAccessor(UnsafeAccessorKind.Field, Name = "_age" ) ]
static  extern  ref  int  GetAgeField (Person counter )为什么它这么快? 对于C#来说,私有类型是OOP语言的定义。它定义了什么是私有类型,它的行为是什么。Unsafe Accessor就能猜到意图了
3,2,1. 上汇编!!!
.NET 9中的改进 支持泛型,更优雅。https://learn.microsoft.com/zh-cn/dotnet/core/compatibility/core-libraries/9.0/unsafeaccessor-generics 
参考资料 https://blog.csdn.net/sD7O95O/article/details/133002995 https://learn.microsoft.com/zh-cn/dotnet/api/system.runtime.compilerservices.unsafeaccessorattribute?view=net-8.0 
转自https://www.cnblogs.com/lmy5215006/p/18545334