2017-07-20 10 views
2

.NETアプリケーションでは、「同じ」オブジェクトの定義を持つ2つのリモートWCFサービスを消費しています。CoreService.CustomerおよびProductService.Customer同じ関数をキャストしたり、別のオブジェクト型を入力するダック

「同じ」という言葉は意図的に引用符で囲まれています。名前空間の観点からは、それらは2つの異なるエンティティです。しかし、これは、サービスが生成/消費される方法のために純粋です。この状況では、両方のオブジェクトがバックエンドシステム内の同じライブラリに由来するという事実があります。

具体的なシナリオでは、両方のオブジェクトタイプから要素を抽出する必要があります。私がしたいことは、過負荷を提供することで、鋳造やボクシングの方法により、同じ操作を再利用するために実際にある

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); 
} 

この作品は、性質を考慮すると、理にかなっているという事実両方のオブジェクトの値が一致することが保証されています。しかし、これは高価であり、かなり不必要なようです。

もう1つのオプションはimplicit conversion operatorです。しかし、オブジェクトがサービス生成されていることを考えると、私は両方のオブジェクトを演算子で拡張する方法はよく見ていません。

これがベストプラクティスであるかどうかは、主なポイントは議論の余地がありません。異なるサービス参照間で同じ共有オブジェクトを再利用するような選択肢を見つける方法もありません。私はこのハックの厄介さをよく知っています。私はそれが言語の観点から興味深い課題であると言えば十分です。

そして、それは実際の質問に私をもたらします:2「異なるが、同じ」オブジェクト間で安価なキャスト/ボクシングを作り、これを嚥下にコンパイラをだますために、よりエレガントな方法または、より良いプットがあり、 _ExtractFoo()の実装を再利用できるようにしますか?

更新I -外部Webサービスを使用する場合、共通のインタフェースを使用することはオプションではありません。また、Customerオブジェクトには、ネストされたプロパティと子オブジェクトのかなり深い階層があることがわかります。 AutoMapperやマニュアルマップのようなものを使うと面倒です(エラーが発生しにくいことは言うまでもありません)。

アップデートII - またはその実装 - -将来の参考のために、私は/質問私の問題は、私は_ExtractFoo()方法を変更することができる方法であることを説明しようとしたので、それはCoreService.CustomerProductService.Customerの両方に適用することができます(とら上記のすべてを考慮してください)。答えとして提供されているものは私の意見では確かに選択肢として実行可能ですが、「他のすべての選択肢を挙げてください」という意味で未解決の質問であることは間違いありません。私の頭の上オフ

+2

両方のオブジェクトで同じインターフェイスを実装することはできないとしますか? – DavidG

+0

実際、それは残念なことにオプションではありません。 –

+0

質問は非常に広いようです。詳細はほとんどないので、あまりにも多くを推論しなければならず、それは可能な限り多くの回答につながります。つまり、C#の "duck typing"では、一般的に 'dynamic'を使いたいということです。上の唯一の例は、 '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(); 
    } 
    

    をあなたは、あなたが望んだ場合、customerProductService.CustomerまたはCoreService.Customerかのいずれかであることを保証するために、いくつかのチェックを追加することができますあなたはいくらか安全です。

+0

ありがとう@DavidG - あなたは私が質問を編集したのとほぼ同じ時に答えました。あなたはオプション4について少し詳しく説明できますか、私はあなたがそれをどういう意味を理解していませんか? –

+0

あなたの 'ExtractFoo'メソッドが具体的な型を取る場所は、' dynamic'に変更し、オブジェクトを渡す前にキャストしないでください。 – DavidG

+0

ソリューション番号。 5はまさに私が探していたものです。私は完全にそれをオプションとして見落としました!おそらく鋳造物を稼働させるためにトンネルが見えるかもしれません。ありがとう。 –

関連する問題