2017-07-20 29 views
2

在.NET應用程序中,我使用了兩個遠程WCF服務,它們都具有「相同」對象的定義:CoreService.CustomerProductService.Customer通過強制轉換重複使用相同的函數,或者使用鴨子鍵入不同的對象類型

「相同」是故意放在引號;從名稱空間的角度來看,它們是兩個不同的實體。但是,這是純粹的,因爲服務的生成/消耗方式。在這種情況下,兩個對象都來自後端系統中的相同庫是一個給定的事實。

在特定場景中,我需要從兩種對象類型中提取內容。我這是最初建於一個特定的實例中的一個功能:

private static string _ExtractFoo(CoreService.Customer customer) { 
    // removed for the sake of brevity 
    return string.Empty; 
} 

我想實際上是重複使用相同的操作,通過提供過載,並通過鑄造或拳擊的方式簡單地試圖說服這兩個編譯器和運行時,這將只是工作(如果你願意簡單地想duck typing)。

以下情形的不工作:

private static string _ExtractFoo(ProductService.Customer customer) { 

    // #1 - Cast, results in error: 
    //  Cannot convert type ... via a built-in conversion 
    return _ExtractFoo((CoreService.Customer) customer); 

    // #2 - Safe cast, results in error: 
    //  Cannot convert type ... via a built-in conversion 
    return _ExtractFoo(customer as CoreService.Customer); 

    // #3 - Works for compiler, breaks at runtime where 'casted' is null 
    dynamic d = customer; 
    var casted = d as CoreService.Customer; 
    return _ExtractFoo(casted); 
} 

一個簡單的修正,做工作被序列化首先JSON:

private static string _ExtractFoo(ProductService.Customer customer) { 
     // awkward hack - but it blends! 
     var serialized = JsonConvert.SerializeObject(customer); 
     var deserialized = JsonConvert.DeserializeObject<CoreService.Customer>(serialized); 

     return _ExtractFoo(deserialized); 
} 

,這個作品其實是有道理的,考慮到性能並且兩個對象的值保證是匹配的。雖然,這是昂貴的,似乎很沒必要。

另一種選擇是使用implicit conversion operator。但是,考慮到對象是服務生成的,我不太清楚如何使用操作符來擴展這兩個對象。

關於這是不是最佳實踐,關鍵不在於辯論。也不知道如何找到像在不同的服務引用之間重複使用相同的共享對象的選擇。我很清楚這種黑客的尷尬。只要說從語言的角度來看,我覺得這是一個有趣的挑戰就足夠了。

這讓我想起了實際的問題:有沒有更優雅的方式愚弄編譯器吞噬這個或更好的投入,使兩個「不同但相同」的對象之間更便宜的投/允許我重新使用_ExtractFoo()實現?

更新I -使外部Web服務使用通用接口不是一個選項。此外,可能很高興知道Customer對象具有相當深層次的嵌套屬性和子對象;使用類似AutoMapper的東西,或手動地圖,會很麻煩(更不用說容易出錯)。

更新II -對於將來參考起見,我試圖解釋,我的問題/問題是我怎麼能修改_ExtractFoo()方法 - 或其執行 - 因此它可以被應用到CoreService.CustomerProductService.Customer(攝以上的一切考慮在內)。從「請列出所有其他選項」的意義上來說,這絕對不是一個開放的問題,儘管在我看來,答案中提供的答案在選項上當然是可行的。

+2

假設你不能讓兩個對象實現相同的接口? – DavidG

+0

事實上,這不是一個不幸的選擇。 –

+0

這個問題看起來非常廣泛。細節太少,我們不得不推斷太多,導致太多可能的答案。也就是說,在C#中,「duck typing」通常意味着你想使用'dynamic'。上面使用'dynamic'的唯一示例,它看起來並不像你做得正確。 「動態」的重點不是強制轉換爲特定類型,而是要訪問您希望存在的指定成員。即**鴨打字**。只要你選擇了某種特定的類型,就會失敗,因爲你剛剛回到了傳統C#的靜態類型世界。 –

回答

1

關閉我的頭頂,你的選擇是:

  1. 同時獲得源類來實現相同的接口,並且通過周圍,而不是具體類型。這將是更好的選擇,但我猜這是不可能的。
  2. 反序列化和序列化返回以在類型之間轉換。你已經有了這個代碼,但是像你說的那樣可能很慢。
  3. 使用映射庫(如AutoMapper)在類型之間進行轉換。這是非常快的,但需要你從Nuget引入外部庫(我已經多次使用AutoMapper)
  4. 自己手動映射屬性。這可能是最快的代碼,但寫得很糟糕。
  5. 使用dynamic一路下來,不只是在頂部。您會丟失編譯時類型檢查,但它應該相當快。例如,而不是有這樣的功能:

    public static string _ExtractFoo(ProductService.Customer customer) 
    { 
        return customer.DoSomethingExciting(); 
    } 
    

    你必須這樣:

    public static string _ExtractFoo(dynamic customer) 
    { 
        return customer.DoSomethingExciting(); 
    } 
    

    你可以,如果你想添加一些檢查,以確保customer要麼ProductService.CustomerCoreService.Customer如果你想要一些安全。

+0

謝謝@DavidG - 在我編輯問題的同時,您幾乎可以回答。你能否詳細說一下選項4,我不太明白你的意思? –

+0

那麼你的'ExtractFoo'方法需要一個具體的類型,把它改成'dynamic',並且在傳入之前不要拋出對象。 – DavidG

+0

解決方案no。 5正是我所期待的;我完全忽略了這個選項!可能也是「隧道觀察」讓演員投入工作。謝謝。 –

相關問題