MissingMethodException 問題及使用 Reflection 來一勞永逸
最近同事跟我都被同樣(類似)的東西陰到,想到就來作個筆記XD
在一個大型系統中,一定會有模組化的動作產生,不同的功能會切成一個一個的動態連結函式庫(Dynamic-link library; dll),而依參考層級也有分上層跟底層,通常底層是類似地基的東西,也是被最多人參考的。
而這次遇到的問題就是在修改底層時產生的問題
我在開發環境時修改了底層,但因為公司的 Publish 習慣是修改哪個類別庫,就只置換該 dll 檔案,而我在舊有的函式中加了一個 Optional 的參數,但在正式環境執行後會得到 MissingMethodException 的 Exception 訊息
原因當然是因為上層的類別庫紀錄的 Method 簽署與底層上的實際的方法參數不同,但就是這個問題也讓我搞了許久!
解決方法有
1. 針對所有呼叫到該函式相關的 dll 檔全部都更新,這樣相對應的 Method delegate 也會被更新,自然就能找到對應了!
2. 改用 Reflection 的方式來呼叫
Reflection 是個很有用的工具,他可以讓你的程式在執行過程中檢視類別的原始樣貌(包括變數、擁有的方法、擁有的 Property (抱歉這個我真的不會翻),更甚至方法需要給予什麼樣的參數以進行呼叫全都可以透過這個看到,以下將針對這個例子寫一個方法
但必需提醒的是,使用鏡射的方法去呼叫執行函式,就會有一定程度上的效能損失,如果可以,會建議使用方法 1 來解決這個問題!不但效能較佳,而且程式碼上也較為美觀,重點是透過 Reflection 的方法撰寫的話, Intellisense 可沒辦法提供你參數的建議。
Reference:
System.Reflection 命名空間
在一個大型系統中,一定會有模組化的動作產生,不同的功能會切成一個一個的動態連結函式庫(Dynamic-link library; dll),而依參考層級也有分上層跟底層,通常底層是類似地基的東西,也是被最多人參考的。
而這次遇到的問題就是在修改底層時產生的問題
我在開發環境時修改了底層,但因為公司的 Publish 習慣是修改哪個類別庫,就只置換該 dll 檔案,而我在舊有的函式中加了一個 Optional 的參數,但在正式環境執行後會得到 MissingMethodException 的 Exception 訊息
原因當然是因為上層的類別庫紀錄的 Method 簽署與底層上的實際的方法參數不同,但就是這個問題也讓我搞了許久!
解決方法有
1. 針對所有呼叫到該函式相關的 dll 檔全部都更新,這樣相對應的 Method delegate 也會被更新,自然就能找到對應了!
2. 改用 Reflection 的方式來呼叫
Reflection 是個很有用的工具,他可以讓你的程式在執行過程中檢視類別的原始樣貌(包括變數、擁有的方法、擁有的 Property (抱歉這個我真的不會翻),更甚至方法需要給予什麼樣的參數以進行呼叫全都可以透過這個看到,以下將針對這個例子寫一個方法
//if Class1 have a method: Method1(string a, object b, int c = 1, int d = 2) var obj = Assembly.LoadFrom(txtAsyncDll.Text).CreateInstance("Class1"); var typClass1 = obj.GetType(); MethodInfo method = typClass1.GetMethod("Method1"); var colParameter = method.GetParameters(); Dictionary<string, object> dicArgs = new Dictionary<string, object>() { {"a", "Hello World"}, {"b", new object()} }; List<object> objs = new List<object>(); foreach(var Paramter in colParameter) { if (dicArgs.ContainsKey(Paramter.Name)) { objs.Add(dicArgs[Paramter.Name]); } else if (Paramter.IsOptional && Paramter.HasDefaultValue) objs.Add(Type.Missing); else { Type typ = Paramter.ParameterType; objs.Add(typ.IsValueType ? Activator.CreateInstance(typ) : null); } } method.Invoke(obj, objs.ToArray());經過這樣的修改,之後程式在呼叫時會自動映射出該函式的樣貌,所以在執行上就不會有錯
但必需提醒的是,使用鏡射的方法去呼叫執行函式,就會有一定程度上的效能損失,如果可以,會建議使用方法 1 來解決這個問題!不但效能較佳,而且程式碼上也較為美觀,重點是透過 Reflection 的方法撰寫的話, Intellisense 可沒辦法提供你參數的建議。
Reference:
System.Reflection 命名空間
留言
張貼留言