web-dev-qa-db-ja.com

C#オブジェクトのマッピング規則を考え出そうとしています

これはC#ですが、アプリケーションのさまざまなレイヤーに異なるオブジェクトのセットが存在するすべてのOO言語に適用できます。

チーム内で、あるレイヤーのオブジェクトを別のレイヤーのオブジェクトにマッピングするときにコードを配置する場所についての規則を考え出そうとしています。例えば;データ転送オブジェクトをWCFサービスなどで使用されるサービスオブジェクトにマッピングする。私は次の方法が使用されているのを見てきましたが、コードを新しく見た人がどちらを好むか、およびこれらのどれが自然なC#イディオムに最も適しているかを判断しようとしています。

これらの例では、AutoMapperを使用してオブジェクトFooをオブジェクトBarにマッピングしますが、これは任意のマッピングフレームワークに適用されるか、オブジェクト初期化子を使用してFooから手動でBarを作成するだけです。これらのオブジェクトは両方とも同じデータを表しますが、それらは異なるアセンブリにあります。

1)Barのコンストラクタ

public class Bar
{
    public Bar(Foo foo)
    {
        Mapper.Map(foo, this);
    }
}

2)Barのファクトリーメソッド

public class Bar
{
    public static Bar CreateFrom(Foo foo)
    {
        return Mapper.Map<Bar>(foo);
    }
}

3)Fooを返すメソッドBar

public class Foo
{
    public Bar GetBar()
    {
        return Mapper.Map<Bar>(this);
    }
}

4)Fooの明示的な型変換演算子Barにキャストできます

public class Foo
{
    public static explicit operator Bar(Foo foo)
    {
        return Mapper.Map<Bar>(foo);
    }
}

5)ファクトリーパターンのいくつかの実装

public class BarFactory : IFactory<Bar>
{
    public Bar Create(Foo foo)
    {
        return Mapper.Map<Bar>(foo);
    }
}

6)必要なピースコードで実行するだけ

    public void SomeMethod()
    {
        Foo foo = fooRepository.GetFoo();

        //I need it to be bar now...
        Bar bar = Mapper.Map<Bar>(foo);

    }

免責事項:この例ではAutoMapperを使用していなかったと思います。ここで「AutoMapper」が「IMappingProvider」または「IObjectConverter」または何かを読んでいると想像してみてください

5
jcharlesworthuk

すべての場合において、私は#5を好みます。 1-2-3-4のサンプルコードでは、ドメインオブジェクトは彼に関連するDTOオブジェクトを知っている必要はないと思います。

あなたが持っているとしましょう

public class User
{
    ... some properties ...
} 

public class UserThumbnail
{
    ... some properties ...
} 

ドメインモデルオブジェクト(User)は、DTOオブジェクト(UserThumbnail)がユーザーのプロパティを使用していることを認識する必要はありません。これらのクラス間の結合を追加し、DTOオブジェクト(UserThumbnail)を作成する責任がドメインオブジェクト(ユーザー)。

したがって、ビジネスのユースケースで、ユーザーがUserThumbnailを作成できるように指定されていない場合は、作成しないでください。そのため、この場合はFactoryなどのクラスを使用する必要があります。DTOオブジェクトはドメインオブジェクトを汚染しないためです。その場合にファクトリが使用されると、ドメインオブジェクトはDTOオブジェクトが存在することさえ知りません。

#6の場合、AutoMapperを別のマッピングツールに変更する場合は、コードを検索する必要があります。ファクトリを使用した場合、すべてのAutoMapper呼び出しが存在することがわかります。

Mapper.Mapは2つのことを実行しています。インスタンスを作成し、プロパティをマップします。ファクトリパターンは、オブジェクト作成コードを分離する場合のソリューションです。

4

通常、私は#3を好みます。GetBarは、どこから来て何を取得しているのかが非常に明白ですが、この場合、クラスのマッピングで変換演算子をよく使用します。

しかし、マッピングはキャストしているようには見えません。オブジェクト(GetBarを使用する場所)に含まれていない新しいものを実際に作成し、それを変換するだけです(演算子バー)。

したがって、この場合はCreateFromを使用します。新しいマップオブジェクトを作成して、Fooに関連する他の何かを表していることは明らかです。

1
gbjbaanb

マッパークラスを作成し、データをあるタイプから別のタイプに手動でマップします。ええ、それは定型文ですが、完全に制御されており、それは単純であり、それは仕事をします。モデルオブジェクトにはWCFの戻り値の型に関する知識がないため、モデルアセンブリには含めないでください。

public class FooMapper
{
    public Foo Map(Bar bar)
    {
        return new Foo
            {
                ValueOne = bar.ValueOne,
                ValueTwo = bar.ValueTwo,
                ....
            };
    }
}
1
Tom Pickles