2016-07-09 14 views
1

ジェネリック型マッパーを実装したいのですが、ジェネリック型の制約に関する問題に苦しんでいます。ジェネリック型の厳密な型制約 - C#

Iが有しており、以下で定義されるエンティティマッパークラス:

public class Foo 
{ 
    public long FooLongProp { get; set; } 

    public decimal? FooDecimalNullProp { get; set; } 

    public string FooStringProp { get; set; } 
} 

public class Bar 
{ 
    public long? BarLongNullProp { get; set; } 

    public decimal BarDecimalProp { get; set; } 
} 

次のようにマッピングが行われている:

public class EntityMapper<TDto, TEntity> 
{ 
    public void RegisterMapping<TDtoProperty, TEntityProperty>(
     Expression<Func<TDto, TDtoProperty>> expressionFrom, 
     Expression<Func<TEntity, TEntityProperty>> expressionTo, 
     Func<TDtoProperty, TEntityProperty> mapper) 
    { 
     // mapping 
    } 
} 

Iはまた、私がマッピングするプロパティ2つのクラスを持っています

public void Map() 
{ 
    var mapper = new EntityMapper<Foo, Bar>(); 

    mapper.RegisterMapping(x => x.FooLongProp, x => x.BarLongNullProp, x => x); // FooLongProp -> long, BarLongNullProp -> long? 
    mapper.RegisterMapping(x => x.FooDecimalNullProp, x => x.BarLongNullProp, x => x); // FooDecimalNullProp -> decimal?, BarLongNullProp -> long? 
    mapper.RegisterMapping(x => x.FooDecimalNullProp, x => x.BarDecimalProp, x => x); // FooDecimalNullProp -> decimal?, BarDecimalProp -> decimal 

    mapper.RegisterMapping(x => x.FooStringProp, x => x.BarLongNullProp, x => x); // FooStringProp -> string, BarLongNullProp -> long? 
} 

RegisterMappingの3番目のパラメータが正確に同じtを返すようにしたいype、としてTEntityProperty。 残念ながら、コンパイラは、エラーとして以下のlong -> long?間のマッピングのコードを報告しません。それはエラーマッピングdecimal? -> decimal(実行時に壊れる)も報告しません。

コンパイラがエラーを報告する唯一の場所は、キャストする行です。string -> decimal?

だから私は、質問を次ています

  1. は、なぜ最初の3つのマッピングは、私が期待通りに動作しませんの?コンパイラが型を適切に解決しないと思われる のようです。
  2. ジェネリック制約で完全に同じ型制約を指定する方法はありますか?
  3. 私がやりたいことを達成し、コンパイル時にエラーが発生する可能性はありますか?

他の提案、ご意見は歓迎します。

+0

使用[Automapper](http://automapper.org/) – dotctor

+0

生憎私はそれを行うことはできません - 私はマッピング以外に追加の操作を行う必要があります。私はautomapperを使ってマッピング操作だけを行うことができましたが、それは 'RegisterMapping'メソッドの中にあります。 – rebelkk

答えて

0
mapper.RegisterMapping(x => x.FooLongProp, x => x.BarLongNullProp, x => x); // FooLongProp -> long, BarLongNullProp -> long? 
  1. x => x.FooLongPropコンパイラ推論(Expression<Func<Foo, long>>
  2. x => x.BarLongNullPropコンパイラ推論(Expression<Func<Bar, long?>>
  3. x => xコンパイラ推論(Func<long, long?>>

mapper.RegisterMapping(x => x.FooDecimalNullProp, x => x.BarLongNullProp, x => x); // FooDecimalNullProp -> decimal?, BarLongNullProp -> long? 
  1. x => x.FooDecimalNullPropコンパイラ推論(Expression<Func<Foo, decimal?>>

  2. x => xコンパイラ推論(Func<decimal?, decimal?>>)!なぜ?? Becuase x=>xFunc<type of x,type of x>

  3. x => x.BarLongNullPropコンパイラの推論(Expression<Func<Bar, decimal?>>)です!どうして? 2行目のためにアップキャストlong?からdecimal?になるので、ジェネリックパラメータと一致することができます。


類似したものが、他の場合に起こります。最後のケースでは、コンパイラはFunc<string, long?>を探します。 x=>xFunc<string,string>)を指定すると、コンパイラはジェネリック型の正しい型を推論できないため、失敗します。メソッド呼び出しの上にマウスカーソルを置くと、コンパイラによって推論されるジェネリックパラメータが表示されます。ラムダの明示的な入力を指定する必要があります。

mapper.RegisterMapping(x => x.FooLongProp, x => x.BarLongNullProp, x => x); 
mapper.RegisterMapping(x => x.FooDecimalNullProp, x => x.BarLongNullProp, x => (long?)x); 
mapper.RegisterMapping(x => x.FooDecimalNullProp, x => x.BarDecimalProp, x => (decimal)x); 

mapper.RegisterMapping(x => x.FooStringProp, x => x.BarLongNullProp, x => (long?)(object)x); //or any lambda which returns long? 
関連する問題