C#進階之路(七)反射的應用
阿新 • • 發佈:2018-12-07
反射在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; } }