学习笔记:C#高级进阶语法——反射(Reflection)
1.学习笔记:C#高级进阶语法——反射(Reflection)
2.学习笔记:C#高级进阶语法——泛型(Generic)3.学习笔记:C#高级进阶语法——特性(Attribute)4.学习笔记:C#高级进阶语法——委托(Delegate)二、反射(Reflection)
1、反射:就是一个微软提供的帮助类库,可以解析并使用元数据。
2、exe/dll----ILSpy工具打开会包含matedata(元数据),描述了当前程序集中有哪些元素成员
3、反射动态加载dll文件,调用方法
{ //1、引用,2、new,3、调方法 IDBHelper helper = new SqlServerHelper(); helper.Query(); } { //反射方式: //1、动态加载dll文件 Assembly assembly1 = Assembly.Load("Business.DB.SqlServer");//带上dll名称,在当前执行目录下找 Assembly assembly2 = Assembly.LoadFrom("Business.DB.SqlServer.dll");//带上.dll后缀名,在当前执行目录下找 Assembly assembly3 = Assembly.LoadFile("D:\\GIT\\Advanced\\Advanced" + "\\MyReflection\\Business.DB.SqlServer.dll");//带上全路径 //2、获取类型名称 Type type = assembly1.GetType("Business.DB.SqlServer.SqlServerHelper"); //3、使用反射创建对象 object? oInstance = Activator.CreateInstance(type); //4、类型转换 IDBHelper helper = oInstance as IDBHelper; //5、调用方法 helper.Query(); dynamic oInstance1 = Activator.CreateInstance(type); oInstance1.Query(); oInstance1.fasdfdsfqwe123412();//不存在的方法也可以写,不严谨的 //在不知道dll档中有什么内容可以这样获取所有的 //foreach (var type in assembly1.GetTypes()) //{ // Console.WriteLine($"Type.Name={type.Name}"); // foreach (var item in type.GetMethods()) // { // Console.WriteLine($"Method.Name={item.Name}"); // } // foreach (var item in type.GetProperties()) // { // Console.WriteLine($"Property.Name={item.Name}"); // } // foreach (var item in type.GetProperties()) // { // Console.WriteLine($"Property.Name={item.Name}"); // } //} }
4、反射+配置文件+简单工厂---实现程序的可配置化
应用:比如动态更新dll版本,比如数据库从SqlServer切换到Mysql
using Business.DB.Interface; using Microsoft.Extensions.Configuration; using System; using System.Reflection; namespace MyReflecttion { public class SimpleFactory { /// <summary> /// 提供一个返回IDBHelper的方法 /// 1、完全断开了对于普通类的依赖 /// 2、配置文件的修改,不需要停止项目运行 /// 3、反射+配置文件+简单工厂===程序的可配置化, 可以扩展化~ /// </summary> /// <returns></returns> public static IDBHelper CreateInstance() { string ReflictionConfig = CustomConfigManager.GetConfig("ReflictionConfig"); string[] strings= ReflictionConfig.Split(','); string dllName = strings[1]; string typeName = strings[0]; Assembly assembly = Assembly.LoadFrom(dllName); Type type = assembly.GetType(typeName); object? oInstance = Activator.CreateInstance(type); IDBHelper dBHelper = oInstance as IDBHelper; return dBHelper; } } public static class CustomConfigManager { //Core 读取配置文件:appsettings //1.Microsoft.Extensions.Configuration; //2.Microsoft.Extensions.Configuration.Json public static string GetConfig(string key) { var builder = new ConfigurationBuilder().AddJsonFile("appsettings.json"); //默认读取 当前运行目录 IConfigurationRoot configuration = builder.Build(); string configValue = configuration.GetSection(key).Value; return configValue; } } }
5、反射黑科技:反射破坏单例,反射可以突破访问修饰符的权限(比如Private私有修饰,可以在类外部调用)
//定义一个单例,构造函数定义为私有的,在类的外部可以调用它。 namespace DB.SqlServer { public sealed class Singleton { private static Singleton _Singleton; private Singleton() { Console.WriteLine("构造函数被调用"); } static Singleton() { _Singleton = new Singleton(); } public static Singleton GetInstance() { return _Singleton; } } }
6、反射调用方法+反射创建对象升级
1、获取要调用的方法名称
2、获取方法的类型,MethodInfo
3、Invoke方法,执行方法
{ //调用普通方法 Assembly assembly = Assembly.LoadFrom("DB.SqlServer.dll"); Type? type = assembly.GetType("DB.SqlServer.SqlServerHelper"); object? oInstance = Activator.CreateInstance(type); MethodInfo query = type.GetMethod("Query"); query.Invoke(oInstance, new object[0]); } { //在反射创建对象的时候,如何指定执行多个构造函数中的某个? Assembly assembly = Assembly.LoadFrom("DB.SqlServer.dll"); Type? type = assembly.GetType("DB.SqlServer.ReflectionTest"); //如果要选择构造函数,在调用方法的时候,直接传入和参数列表匹配的参数即可 object? oInstance = Activator.CreateInstance(type); object? oInstance1 = Activator.CreateInstance(type,new object[] {"你好" }); object? oInstance2 = Activator.CreateInstance(type,new object[] { 1233}); object? oInstance3 = Activator.CreateInstance(type,new object[] { "你好",123}); object? oInstance4 = Activator.CreateInstance(type,new object[] { 123,"你好不好"}); } { //执行各种方法 Assembly assembly = Assembly.LoadFrom("DB.SqlServer.dll"); Type? type = assembly.GetType("DB.SqlServer.SqlServerHelper"); object? oInstance = Activator.CreateInstance(type); //执行Show1 --无参方法 MethodInfo query = type.GetMethod("Show1"); query.Invoke(oInstance, null); //执行Show2 --带参方法 MethodInfo query2 = type.GetMethod("Show2"); query.Invoke(oInstance, [3456]);//传入的参数类型要和方法的参数完全匹配 //执行Show3 --重载方法 //对于重载方法,需要进一步精确查找的是哪个方法 MethodInfo query3 = type.GetMethod("Show3",new Type[] { typeof(int),typeof(string)}); query.Invoke(oInstance, new object[] { 123412,"你好我不好"}); //执行Show4 --私有方法 MethodInfo query4 = type.GetMethod("Show4", BindingFlags.Instance | BindingFlags.NonPublic); query4.Invoke(oInstance, new object[] { "你好我不好" }); //执行Show5 --静态方法 MethodInfo query5 = type.GetMethod("Show4"); query5.Invoke(null, new object[] { "你好我不好" });//静态类不需要类的实例就可以执行 }
//测试类如下 namespace DB.SqlServer { /// <summary> /// 反射测试类 /// </summary> public class ReflectionTest { #region Identity /// <summary> /// 无参构造函数 /// </summary> public ReflectionTest() { Console.WriteLine($"这里是{GetType()}无参数构造函数"); } /// <summary> /// 带参数构造函数 /// </summary> /// <param name="name"></param> public ReflectionTest(string name) { Console.WriteLine($"这里是{GetType()} 有参数构造函数"); } public ReflectionTest(int id) { Console.WriteLine($"这里是{GetType()} 有参数构造函数"); } public ReflectionTest(int id, string name) { //typeof(int); //Type //id.GetType(); Console.WriteLine($"这里是{GetType()} 有参数构造函数"); } public ReflectionTest(string name, int id) { //typeof(int); //Type //id.GetType(); Console.WriteLine($"这里是{GetType()} 有参数构造函数"); } #endregion #region Method /// <summary> /// 无参方法 /// </summary> public void Show1() { Console.WriteLine($"这里是{GetType()}的Show1"); } /// <summary> /// 有参数方法 /// </summary> /// <param name="id"></param> public void Show2(int id) { Console.WriteLine($"这里是{GetType()}的Show2"); } /// <summary> /// 重载方法之一 /// </summary> /// <param name="id"></param> /// <param name="name"></param> public void Show3(int id, string name) { Console.WriteLine($"这里是{GetType()}的Show3"); } /// <summary> /// 重载方法之二 /// </summary> /// <param name="name"></param> /// <param name="id"></param> public void Show3(string name, int id) { Console.WriteLine($"这里是{GetType()}的Show3_2"); } /// <summary> /// 重载方法之三 /// </summary> /// <param name="id"></param> public void Show3(int id) { Console.WriteLine($"这里是{GetType()}的Show3_3"); } /// <summary> /// 重载方法之四 /// </summary> /// <param name="name"></param> public void Show3(string name) { Console.WriteLine("这里是{this.GetType()}的Show3_4"); } /// <summary> /// 重载方法之五 /// </summary> public void Show3() { Console.WriteLine($"这里是{GetType()}的Show3_1"); } /// <summary> /// 私有方法 /// </summary> /// <param name="name"></param> private void Show4(string name) //肯定是可以的 { Console.WriteLine($"这里是{GetType()}的Show4"); } /// <summary> /// 静态方法 /// </summary> /// <param name="name"></param> public static void Show5(string name) { Console.WriteLine($"这里是{typeof(ReflectionTest)}的Show5"); } #endregion } }
7、泛型类、泛型方法调用
{ //普通类的泛型方法调用 Assembly assembly = Assembly.LoadFrom("DB.SqlServer.dll"); Type type = assembly.GetType("DB.SqlServer.GenericMethod"); object? oInstance = Activator.CreateInstance(type); MethodInfo show = type.GetMethod("Show"); MethodInfo generic = show.MakeGenericMethod(new Type[] { typeof(int), typeof(string), typeof(DateTime) }); generic.Invoke(oInstance,new object[] { 123,"1234",DateTime.Now}); } { //泛型类的普通方法调用 Assembly assembly = Assembly.LoadFrom("DB.SqlServer.dll"); Type type = assembly.GetType("DB.SqlServer.GenericClass`3"); Type typeG = type.MakeGenericType(new Type[] { typeof(int), typeof(string), typeof(DateTime) }); object? oInstance = Activator.CreateInstance(typeG); MethodInfo show = typeG.GetMethod("Show"); show.Invoke(oInstance, new object[] { 123, "1234", DateTime.Now }); } { //泛型类的泛型方法调用 Assembly assembly = Assembly.LoadFrom("DB.SqlServer.dll"); Type type = assembly.GetType("DB.SqlServer.GenericDouble`1"); Type typeG = type.MakeGenericType(new Type[] { typeof(int) }); object? oInstance = Activator.CreateInstance(typeG); MethodInfo show = typeG.GetMethod("Show"); MethodInfo generic = show.MakeGenericMethod(new Type[] { typeof(string), typeof(DateTime) }); generic.Invoke(oInstance, new object[] { 123, "1234", DateTime.Now }); }
//测试类如下 namespace DB.SqlServer { public class GenericMethod { public void Show<T, W, X>(T t, W w, X x) { Console.WriteLine($"t.type={t.GetType().Name},w.type={w.GetType().Name},x.type={x.GetType().Name}"); Console.WriteLine($"T={t},W={w},X={x}"); } } public class GenericClass<T, W, X> { public void Show(T t, W w, X x) { Console.WriteLine($"t.type={t.GetType().Name},w.type={w.GetType().Name},x.type={x.GetType().Name}"); } } public class GenericDouble<T> { public void Show<W, X>(T t, W w, X x) { Console.WriteLine($"t.type={t.GetType().Name},w.type={w.GetType().Name},x.type={x.GetType().Name}"); } } }
8、反射的局限性---性能问题
反射方式比普通方式的耗时,高一倍以上。
反射不否认他有性能损失,但是只要程序员足够优秀,性能是可以得到优化的,可以放心使用
using DB.Interface; using DB.SqlServer; using System.Diagnostics; using System.Reflection; namespace MyReflection { public class Monitor { public static void Show() { Console.WriteLine("*******************Monitor*******************"); long commonTime = 0; long reflectionTime = 0; { Stopwatch watch = new Stopwatch(); watch.Start(); for (int i = 0; i < 1000_000; i++) //1000000000 { IDBHelper iDBHelper = new SqlServerHelper(); iDBHelper.Query(); } watch.Stop(); commonTime = watch.ElapsedMilliseconds; } { Stopwatch watch = new Stopwatch(); watch.Start(); Assembly assembly = Assembly.LoadFrom("DB.SqlServer.dll");//1 动态加载 Type dbHelperType = assembly.GetType("DB.SqlServer.SqlServerHelper");//2 获取类型 for (int i = 0; i < 1000_000; i++) { //Assembly assembly = Assembly.LoadFrom("DB.SqlServer.dll");//1 动态加载 //Type dbHelperType = assembly.GetType("DB.SqlServer.SqlServerHelper");//2 获取类型 object oDBHelper = Activator.CreateInstance(dbHelperType);//3 创建对象 IDBHelper dbHelper = (IDBHelper)oDBHelper;//4 接口强制转换 dbHelper.Query();//5 方法调用 } watch.Stop(); reflectionTime = watch.ElapsedMilliseconds; } Console.WriteLine($"commonTime={commonTime} reflectionTime={reflectionTime}"); } } }
9、反射调用字段属性
{ //反射调用字段属性 Type type = typeof(People); object oInstance = Activator.CreateInstance(type); //反射赋值 foreach (PropertyInfo prop in type.GetProperties()) { if (prop.Name == "Id") { prop.SetValue(oInstance, 1234); } else if (prop.Name == "Name") { prop.SetValue(oInstance, "RoseLoves"); } } //反射取值 foreach (PropertyInfo prop in type.GetProperties()) { Console.WriteLine($"{prop.Name} = {prop.GetValue(oInstance)}"); } }
10、反射+ADO.NET 实现ORM框架
1、实现基本的查询功能
using DB.Interface; using Microsoft.Data.SqlClient; using System.Reflection; namespace DB.SqlServer { public class SqlServerHelper : IDBHelper { private readonly string _ConnectionStr; public SqlServerHelper(){ } public SqlServerHelper(string connectionStr) { _ConnectionStr = connectionStr; } public void Query() { } public List<T> GetCompany<T>(int id) { //1.准备数据库连接字符串 //_ConnectionStr //2.创建连接对象 SqlConnection connection = new SqlConnection(_ConnectionStr); connection.Open();//打开连接 //反射创建属性 List<T> list = new List<T>(); Type type = typeof(T); object oInstance = Activator.CreateInstance(type); //3.准备命令,Sql语句 //string sql = $"SELECT * FROM Company WHERE ID = '{id}'"; string sql = $"SELECT {string.Join(',', type.GetProperties().Select(c => c.Name).ToList())} FROM {type.Name} WHERE ID = {id}"; //4.准备命令执行对象 SqlCommand command = new SqlCommand(sql, connection); //执行命令(执行sql语句) SqlDataReader reader = command.ExecuteReader(); while (reader.Read()) { //反射取值 foreach (PropertyInfo prop in type.GetProperties()) { prop.SetValue(oInstance, reader[prop.Name] is DBNull ? null : reader[prop.Name]); } list.Add((T)oInstance); } return list; } } }
{ //反射+AOD.NET 实现ORM框架 string constr = "Data Source=LAPTOP-FR93A6FM;Initial Catalog=CustomerDB;Persist Security Info=True;User ID=sa;Password=Xjc000000;Trust Server Certificate=True"; SqlServerHelper sqlServerHelper = new SqlServerHelper(constr); var c = sqlServerHelper.GetCompany<Company>(13479); Console.WriteLine(c[0].Name); var S = sqlServerHelper.GetCompany<SysUser>(13479); }
2、但是在上述操作中,SQL语句在每次执行都要创建一次,用反射创建对象会有性能损耗。所以可以用缓存
Sql语句的生成特点:
a、同类型的sql语句是一样的
b、同一类型的操作,sql语句只需要生成一次
c、如果要缓存,为每一个类型做一个缓存,也就是泛型缓存:泛型缓存的本质是泛型类。
namespace DB.SqlServer { public class SqlBuilder<T> { private static string _QuerySql; /// <summary> /// 使用静态构造函数初始化 /// </summary> static SqlBuilder() { Type type = typeof(T); _QuerySql = $"SELECT {string.Join(',', type.GetProperties().Select(c => c.Name).ToList())} FROM {type.Name} WHERE ID ="; } public static string GetQuerySql(int id) => $"{_QuerySql} {id}"; } }
using DB.Interface; using DB.Models; using Microsoft.Data.SqlClient; using System.Reflection; namespace DB.SqlServer { public class SqlServerHelper : IDBHelper { private readonly string _ConnectionStr; public SqlServerHelper() { } public SqlServerHelper(string connectionStr) { _ConnectionStr = connectionStr; } public void Query() { } public List<T> GetCompany<T>(int id) where T : BaseModel//要求实体类必须有一个Id的字段 { //1.准备数据库连接字符串 //_ConnectionStr //2.创建连接对象 SqlConnection connection = new SqlConnection(_ConnectionStr); connection.Open();//打开连接 //反射创建属性 List<T> list = new List<T>(); Type type = typeof(T); object oInstance = Activator.CreateInstance(type); //3.准备命令,Sql语句 //string sql = $"SELECT * FROM Company WHERE ID = '{id}'"; //string sql = $"SELECT {string.Join(',', type.GetProperties().Select(c => c.Name).ToList())} FROM {type.Name} WHERE ID = {id}"; string sql = SqlBuilder<T>.GetQuerySql(id); //4.准备命令执行对象 SqlCommand command = new SqlCommand(sql, connection); //执行命令(执行sql语句) SqlDataReader reader = command.ExecuteReader(); while (reader.Read()) { //反射取值 foreach (PropertyInfo prop in type.GetProperties()) { prop.SetValue(oInstance, reader[prop.Name] is DBNull ? null : reader[prop.Name]); } list.Add((T)oInstance); } return list; } } }
11、反射生成程序集
原始:程序是设计好的,然后通过运行时环境去驱动,去执行设计好的程序指令;
EMit:在程序运行的过程中,动态的生成一堆新的程序出来-------程序造程序。
在程序运行时,要能够动态的生成程序集、类、结构、变量、方法、属性、字段。。。。。。
程序集(dll/exe)--->moudle----->类------>方法、属性。。。。。他们是逐级的包含关系
using System.Reflection; using System.Reflection.Emit; namespace MyReflecttion { public class ReflectionEmit { //一般的,使用反射发出(reflection emit)可能会是这样子的步骤: //步骤一、创建一个新的程序集(程序集是动态的存在于内存中或把它们保存到磁盘上)。 //步骤二、在程序集内部,创建一个模块(module)。 //步骤三、在模块内部,创建一个类型。 //步骤四、给类型添加属性和方法。 //步骤五、产生属性和方法内部的代码 //确切得说,当你使用Reflection.Emit类产生代码时,以上描述的是你实际中要遵循的过程。 public static void Show() { AssemblyName aName = new AssemblyName("DynamicAssemblyExample"); //程序集建造者 AssemblyBuilder ab = AssemblyBuilder.DefineDynamicAssembly(aName, AssemblyBuilderAccess.RunAndCollect); // 对于单个模块程序集,模块名称通常为 //程序集名称加上扩展名。 ModuleBuilder mb = ab.DefineDynamicModule("MyModal"); //基于module 配置要生成的类型 TypeBuilder tb = mb.DefineType("MyDynamicType", TypeAttributes.Public); // 添加int(Int32)类型的私有字段。 FieldBuilder fbNumber = tb.DefineField("m_number", typeof(int), FieldAttributes.Private); // 定义一个接受一个int类型参数的构造函数 // 储存在私人区域。 Type[] parameterTypes = { typeof(int) }; ConstructorBuilder ctor1 = tb.DefineConstructor( MethodAttributes.Public, CallingConventions.Standard, parameterTypes); ILGenerator ctor1IL = ctor1.GetILGenerator(); //对于构造函数,参数0是对新 //实例。在调用base之前将其推到堆栈上 //类构造函数。指定的默认构造函数 //通过传递 //类型(Type.EmptyTypes)到GetConstructor。 ctor1IL.Emit(OpCodes.Ldarg_0); ctor1IL.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes)); //在推送参数之前,先将实例推送到堆栈上 //将被分配给私有字段m\u编号。 ctor1IL.Emit(OpCodes.Ldarg_0); ctor1IL.Emit(OpCodes.Ldarg_1); ctor1IL.Emit(OpCodes.Stfld, fbNumber); ctor1IL.Emit(OpCodes.Ret); //定义无参数构造函数 //定义提供默认值的默认构造函数 //私人领域。对于参数类型,传递空 //类型数组或传递null。 ConstructorBuilder ctor0 = tb.DefineConstructor( MethodAttributes.Public, CallingConventions.Standard, Type.EmptyTypes); ILGenerator ctor0IL = ctor0.GetILGenerator(); //对于构造函数,参数0是对新 //实例。在推送默认值之前将其推送到堆栈上 //值,然后调用构造函数ctor1。 ctor0IL.Emit(OpCodes.Ldarg_0); ctor0IL.Emit(OpCodes.Ldc_I4_S, 42); ctor0IL.Emit(OpCodes.Call, ctor1); ctor0IL.Emit(OpCodes.Ret); //定义一个名为Number的属性,用于获取和设置私有 现场。 //DefineProperty的最后一个参数为null,因为属性没有参数(如果不指定null,则必须 //指定类型对象的数组。对于无参数属性, //使用不带元素的内置数组:Type.EmptyTypes) PropertyBuilder pbNumber = tb.DefineProperty( "Number", PropertyAttributes.HasDefault, typeof(int), null); //属性“set”和属性“get”方法需要特殊的属性集。 MethodAttributes getSetAttr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig; //为Number定义“get”访问器方法。方法返回 //一个整数,没有参数(注意null可以是 //代替类型使用。空类型) MethodBuilder mbNumberGetAccessor = tb.DefineMethod("get_Number", getSetAttr, typeof(int), Type.EmptyTypes); ILGenerator numberGetIL = mbNumberGetAccessor.GetILGenerator(); //对于实例属性,参数0是实例。加载 //实例,然后加载private字段并返回 //堆栈上的字段值。 numberGetIL.Emit(OpCodes.Ldarg_0); numberGetIL.Emit(OpCodes.Ldfld, fbNumber); numberGetIL.Emit(OpCodes.Ret); // 为Number定义“set”访问器方法,该方法没有返回值 //类型并接受一个int(Int32)类型的参数。 MethodBuilder mbNumberSetAccessor = tb.DefineMethod( "set_Number", getSetAttr, null, new Type[] { typeof(int) }); ILGenerator numberSetIL = mbNumberSetAccessor.GetILGenerator(); // 加载实例和数值参数,然后存储 numberSetIL.Emit(OpCodes.Ldarg_0); numberSetIL.Emit(OpCodes.Ldarg_1); numberSetIL.Emit(OpCodes.Stfld, fbNumber); numberSetIL.Emit(OpCodes.Ret); //最后,将“get”和“set”访问器方法映射到 //属性生成器。该属性现在已完成。 pbNumber.SetGetMethod(mbNumberGetAccessor); pbNumber.SetSetMethod(mbNumberSetAccessor); // 定义一个接受整数参数并返回 //该整数与专用字段mèu数的乘积。这个 //同时,参数类型的数组是动态创建的。 MethodBuilder meth = tb.DefineMethod( "MyMethod", MethodAttributes.Public, typeof(int), new Type[] { typeof(int) }); ILGenerator methIL = meth.GetILGenerator(); // 要检索private instance字段,请将实例加载到它 // 属于(参数0)。加载字段后,加载 // 参数一,然后乘。从方法返回 // 上的返回值(两个数字的乘积) 执行堆栈。 methIL.Emit(OpCodes.Ldarg_0); methIL.Emit(OpCodes.Ldfld, fbNumber); methIL.Emit(OpCodes.Ldarg_1); methIL.Emit(OpCodes.Mul); methIL.Emit(OpCodes.Ret); // 完成类型 Type t = tb.CreateType(); // 下一行保存单个模块部件。这个 //需要AssemblyBuilderAccess包含Save。你现在可以了 //在命令提示符下键入“ildasm MyDynamicAsm.dll”,然后 // 检查组件。你也可以写一个程序 //对程序集的引用,并使用MyDynamicType类型。 //ab.bu(aName.Name + ".dll"); //由于AssemblyBuilderAccess包含Run,因此可以 //立即执行。从获取反射对象开始 //方法和属性。 MethodInfo mi = t.GetMethod("MyMethod"); PropertyInfo pi = t.GetProperty("Number"); // 使用默认值创建MyDynamicType的实例 建造师。 object o1 = Activator.CreateInstance(t); // 显示属性的值,然后将其更改为127并 //再次显示。使用null表示属性 //没有索引。 Console.WriteLine("o1.Number: {0}", pi.GetValue(o1, null)); pi.SetValue(o1, 127, null); Console.WriteLine("o1.Number: {0}", pi.GetValue(o1, null)); // 调用MyMethod,传递22,并显示返回值22 // 乘以127。参数必须作为数组传递,即使 // 只有一个。 object[] arguments = { 22 }; Console.WriteLine("o1.MyMethod(22): {0}", mi.Invoke(o1, arguments)); // 使用构造函数创建MyDynamicType的实例 //它指定了m\ U编号。构造函数由 //匹配参数数组中的类型。在这种情况下, // 参数数组是动态创建的。显示 //属性值。 object o2 = Activator.CreateInstance(t, new object[] { 5280 }); Console.WriteLine("o2.Number: {0}", pi.GetValue(o2, null)); } } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通