帶有動態參數的 ChannelFactory 錯誤
ChannelFactory如果我為它提供正確類型的動態對象,則會掛起。dynamic src = "MSFT"; var binding = new BasicHttpBinding(); var endpoint = new EndpointAddress("http://www.restfulwebservices.net/wcf/StockQuoteService.svc"); var channel = new ChannelFactory<IStockQuoteService>(binding, endpoint).CreateChannel(); // this will print just fine Console.WriteLine(channel.GetStockQuote(src as string)); // this will print just fine Console.WriteLine(new StockQuoteServiceClient().GetStockQuote(src)); // this will never print and the application will hang with no exceptions Console.WriteLine(channel.GetStockQuote(src));
- 上面的服務是公開的,不是我的,只要在程式碼中提供的endpoint添加服務引用就可以自己測試這段程式碼;
StockQuoteServiceClient由 Add Service Reference 菜單項創建,並採用動態對象就好了;- 當我在調試時使用 F5 啟動應用程序時,這神奇地不會發生,所有行都列印並且程序正確退出;
- 如果我執行它,然後在執行期間附加調試器,我可以看到它掛在呼叫
channel.GetStockQuote(src);- 如果我不管它,程序會吃掉我所有的記憶;
- 僅當我將自己
ChannelFactory的對象與動態對像一起使用時,它才會掛起,如評論中所述。
ChannelFactory當添加服務引用創建的對象執行良好時,為什麼當它以動態對像作為參數時我的掛起?
當您使用 dynamic 關鍵字時,與動態變數相關的每個程式碼都將由 DLR 在執行時編譯。當您使用動態變數呼叫方法時,實際的方法簽名在編譯時是未知的,並且方法返回類型以及與之相關的所有內容都會創建 Eric Lippert 稱為“動態傳染”的東西:
“正如我上次指出的那樣,當呼叫的參數是動態的時,編譯器也很有可能將呼叫的結果分類為動態的;污點傳播開來。事實上,當您使用幾乎任何運算符時一個動態表達式,結果是動態類型,除了少數例外。(例如,“is”總是返回一個布爾值。)您可以“治愈”一個表達式,通過將其強制轉換為對像或其他任何東西來防止它傳播動態主義您想要的非動態類型;將動態轉換為對像是一種身份轉換。”
WCF 內部使用大量介面和抽象,並且存在關於 DLR 無法解析正確類型的抽象和介面的已知 DLR 限制。(也看看這個 SO 討論)
我能夠使用反射正確呼叫 ChannelFactory 並將參數轉換為其他類型(並且還嘗試使用錯誤的類型呼叫服務)。該問題必須與 DLR 相關。
我無法調試 DLR 編譯,但問題可能與“動態傳染”和介面解析錯誤有關。使用“傳染”,WCF 呼叫的每個部分都可能在執行時編譯,並且類型解析錯誤可能會在某些極端情況下創建一些 endles 循環,例如呼叫基方法的重寫方法實現,而基類被錯誤地解析為同一個孩子班級。
當附加調試器 ( Debugger.IsAttached )時,一些 WCF 內部會執行額外的指令,這些指令通常包含在斷言、檢查和屬性中。額外的指令可能會提供一些資訊來殺死“動態傳染”並避免虛假的無限循環。