C#进阶之路(七)反射的应用
反射在C#中的应用还是很多的,但它对代码的性能有一定影响。
反射的性能:
使用反射来调用类型或者触发方法,或者访问一个字段或者属性时clr 需要做更多的工作:校验参数,检查权限等等,所以速度是非常慢的。所以尽量不要使用反射进行编程,对于打算编写一个动态构造类型(晚绑定)的应用程序,可以采取以下的几种方式进行代替:
1、通过类的继承关系。让该类型从一个编译时可知的基础类型派生出来,在运行时生成该类型的一个实例,将对其的引用放到其基础类型的一个变量中,然后调用该基础类型的虚方法。
2、通过接口实现。在运行时,构建该类型的一个实例,将对其的引用放到其接口类型的一个变量中,然后调用该接口定义的虚方法。
3、通过委托实现。让该类型实现一个方法,其名称和原型都与一个在编译时就已知的委托相符。在运行时先构造该类型的实例,然后在用该方法的对象及名称构造出该委托的实例,接着通过委托调用你想要的方法。这个方法相对与前面两个方法所作的工作要多一些,效率更低一些。
反射创建实例
System.Activator提供了方法来根据类型动态创建对象,比如创建一个DataTable:
Type t = Type.GetType("System.Data.DataTable,System.Data,Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"); DataTable table = (DataTable)Activator.CreateInstance(t);
例二:根据有参数的构造器创建对象
namespace TestSpace { public class TestClass { private string _value; public TestClass(string value) { _value = value; } } } … Type t = Type.GetType(“TestSpace.TestClass”); Object[] constructParms = new object[] {“hello”}; //构造器参数 TestClass obj = (TestClass)Activator.CreateInstance(t,constructParms); …
把参数按照顺序放入一个Object数组中即可
反射执行方法
//获取类型信息 Type t = Type.GetType("TestSpace.TestClass"); //构造器的参数 object[] constuctParms = new object[] { "timmy" }; //根据类型创建对象 object dObj = Activator.CreateInstance(t, constuctParms); //获取方法的信息 MethodInfo method = t.GetMethod("GetValue"); //调用方法的一些标志位,这里的含义是Public并且是实例方法,这也是默认的值 BindingFlags flag = BindingFlags.Public | BindingFlags.Instance; //GetValue方法的参数 object[] parameters = new object[] { "Hello" }; //调用方法,用一个object接收返回值 object returnValue = method.Invoke(dObj, flag, Type.DefaultBinder, parameters, null);
动态创建委托
委托是C#中实现事件的基础,有时候不可避免的要动态的创建委托,实际上委托也是一种类型:System.Delegate,所有的委托都是从这个类派生的
System.Delegate提供了一些静态方法来动态创建一个委托,比如一个委托:
namespace TestSpace { delegate string TestDelegate(string value); public class TestClass { public TestClass() { } public string GetValue(string value) { return value; } } }
使用示例:
TestClass obj = new TestClass(); //获取类型,实际上这里也可以直接用typeof来获取类型 Type t = Type.GetType(“TestSpace.TestClass”); //创建代理,传入类型、创建代理的对象以及方法名称 TestDelegate method = (TestDelegate)Delegate.CreateDelegate(t,obj,”GetValue”); String returnValue = method(“hello”);
批量生成插入SQL
这里要注意的是,你传入的T模型与你数据库中的模型要是相同的。
/// <summary> /// 批量加入MYSQL数据库 /// </summary> /// <param name="list"></param> /// <param name="connectionString"></param> /// <param name="tableName"></param> /// <returns></returns> public static int InsertByList<T>(List<T> list, string connectionString, string tableName) { int count = 0; if (list == null || list.Count <= 0) throw new Exception("List无任何数据"); if (string.IsNullOrEmpty(tableName)) throw new Exception("添加失败!请先设置插入的表名"); // 构建INSERT语句 var sb = new StringBuilder(); sb.Append("Insert into " + tableName + "("); Type type = typeof(T); foreach (var item in type.GetProperties()) { if (item.Name == "UpdateTime") { continue; } sb.Append(item.Name + ","); } sb.Remove(sb.ToString().LastIndexOf(','), 1); sb.Append(") VALUES "); foreach (var item in list) { sb.Append("("); foreach (var pi in type.GetProperties()) { if (pi.Name == "UpdateTime") { continue; } if (pi.PropertyType.Name == "Nullable`1")//可空类型,判定是否为空 { var aa = type.GetProperty(pi.Name)?.GetValue(item, null); if (aa == null) { sb.Append("null,"); } else { sb.Append("'" + type.GetProperty(pi.Name)?.GetValue(item, null)?.ToString().Replace(@"\",@"\\").Replace("'", @"\'") + "',"); } } else { sb.Append("'" + type.GetProperty(pi.Name)?.GetValue(item, null)?.ToString().Replace(@"\", @"\\").Replace("'", @"\'") + "',"); } } sb.Remove(sb.ToString().LastIndexOf(','), 1); sb.Append("),"); } sb.Remove(sb.ToString().LastIndexOf(','), 1); sb.Append(";"); sb.Append("select @@IDENTITY"); using (var con = new MySqlConnection(connectionString)) { con.Open(); using (var cmd = new MySqlCommand(sb.ToString(), con)) { try { count = Convert.ToInt32(cmd.ExecuteScalar()); } catch (Exception ex) { LogHelper.Error("批量sql插入操作失败:" + ex.Message + "--" + ex.Source + "---" + ex.StackTrace); } } } return count; }
判断对象是否已赋值
这里model是要验证的实例
Type type = model.GetType(); bool res= false; //判断实例是否是已经赋值, false 未赋值 true 已经赋值 foreach (var item in type.GetProperties()) { List<string> skipList=new List<string>{"UpdateTime","Id"}; if (skipList.Contains(item.Name)) { continue; } var typeThis =item.PropertyType; var valueDefault = typeThis.IsValueType ? Activator.CreateInstance(typeThis) : null; var gggggg = item.GetValue(model); if (valueDefault==null) { if (gggggg!=null) { res = true; break; } } //如果直接使用== 其实是对引用地址的对比 else if (valueDefault.ToString() !=gggggg.ToString()) { res = true; break; } }