0

たくさんのタイプを他のタイプの束に変換したいと思います。たとえば、、、、の4つのタイプがありSourceA、次の変換があります。SourceBTargetATargetB

  • SourceA => TargetA
  • SourceA => TargetB
  • SourceB => TargetA
  • SourceB => TargetB

基本的に、変換は単純なキャストよりも少し高度です。上記の各ケースについて、独自の戦略が必要です。

私が避けたいのは、メソッドに型を含むいくつかのメソッドがあることです。そのため、次のようなものは必要ありません。

ConvertAtoA

または同様のもの。これが不要な理由は、型が型自体としてではなく文字列として使用されるためです。したがって、型の名前を変更しようとすると、リファクタリングはサポートされません。名前をに変更SourceAするSourceXyzと、メソッドの名前は自動的に変更されませんが、手動で変更する必要があります。

私が欲しいのは、主にリファクタリングのサポートを得るために、これを表現する一般的な方法です。つまり、基本的に次のようなものです。

Convert<SourceA, TargetA>(mySourceValue)

ここでの問題は、すべての型のすべてのロジックを含むジェネリックメソッドなっConvert<TSource, TTarget>てしまうことです(これは明らかな理由から悪い考えです)。

訪問者、戦略、責任の連鎖など、さまざまなデザインパターンをすでに見てきましたが、どれも魅力的ではありませんでした。とにかく、そこのポイントを逃したかどうかはわかりません。

どうすればこの問題を解決できますか?

基本的に、2つの主なターゲットは次のとおりです。

  • 組み合わせごとに個別の変換ロジックを持つ(複雑なメソッドはありません)
  • リファクタリングのサポートがある(文字列としてのタイプなし)

何か案は?

アップデート1: AutoMapperの使用を検討しましたが、希望どおりに機能するかどうかわかりません。私が確実にできることは、次のようなカスタムコンバーターをセットアップすることです。

Mapper.CreateMap<string, DateTime>().ConvertUsing(new DateTimeTypeConverter());

DateTimeしかし、ここでも、コンバーター名の一部としてタイプがあります。ここでもラムダ式を使用できることは知っていますが、コードが非常に長くなるため、コードが醜くなります。とにかく、私はすべてを手に入れることができないのではないかと恐れています...

更新2:Dictionary<string, string>左側に(内容は異なりますが)常に(内容は異なりますが)右側にカスタムクラスがあるという制約を課すことで、問題を緩和できます。だから私が最終的にしたいのは、次のような拡張メソッドです

dictionary.To<TargetA>()

ただし、さまざまなタイプに変換するためのすべてのロジックをTo<T>メソッドに組み込む必要はありません。

4

2 に答える 2

2

拡張メソッドを作成できます。これにより、ターゲットタイプが作成され、そのオブジェクトの入力がジェネリックパラメータータイプに基づいたメソッドに委任されます。

public static class Extensions
{
    public static T ConvertTo<T>(this Dictionary<string, string> dictionary)
        where T : new()
    {
        dynamic target = new T();
        return (T)Extensions.FillFrom(target, dictionary);
    }

    private static object FillFrom(this object obj, 
                                   Dictionary<string, string> dictionary)
    {
        var message = "Conversion to " + obj.GetType() + " is not supported.";
        throw new NotSupportedException(message);
    }

    private static TargetA FillFrom(this TargetA target, 
                                    Dictionary<string, string> dictionary)
    {
        // throw exception if required keys not found
        target.Foo = dictionary["foo"];
        return target;
    }

    private static TargetB FillFrom(this TargetB target, 
                                    Dictionary<string, string> dictionary)
    {
        // throw exception if required keys not found
        target.Bar = dictionary["bar"];
        return target;
    }
}

使用法:

var targetA = dictionary.ConvertTo<TargetA>();

一部のコンバータークラスで使用できるのと同じアプローチ(拡張メソッドが気に入らない場合)。FillFromまた、メソッドを公開することもできます。あなたがそれらを次のように使うことができるより:

var target A = new TargetA().FillFrom(dictionary);
于 2013-01-08T14:12:54.857 に答える
1

わかった :-)

基本的に、私の問題は、ジェネリック型パラメーターによるメソッドのオーバーロードを実行できないことでした。TryXXXそこで、やむを得ず美徳を作り、柄の使用に切り替えました。

私のソリューションは次のようになります。

using System;
using System.Collections.Generic;

namespace HelloWorld
{
    public class Program
    {
        public static void Main ()
        {
            Dictionary<string, string> dict = new Dictionary<string, string> {
                { "a", "b" }
            };

            Dog dog;
            if (dict.TryGet (out dog))
            {
                Console.WriteLine(dog.Color);
            }
        }
    }

    public static class ExtensionMethods
    {
        public static bool TryGet(this Dictionary<string, string> dictionary, out Dog dog)
        {
            dog = new Dog();
            dog.Color = "black / white";
            return true;
        }
    }

    public class Dog
    {
        public string Color { get; set; }
    }
}

このように、メソッド名のどこにもタイプはありませんが、Dog変換するタイプごとに個別のメソッドを持つことができます。

新しい型を追加するということは、型を追加し、拡張メソッドに新しいオーバーロードを追加することを意味しTryGetます。

秘訣はout、メソッドのオーバーロードにパラメーターを使用することです。これは完全に正常に機能します:-)。

于 2013-01-08T15:15:57.413 に答える