、これはあなたが自分自身を維持/書き込みする必要があるコードのようなものではありません。 AutoMapperのようなフレームワークは、攻撃対象の問題を解決するために特別に作られたもので、モデルオブジェクトをDTOに変換します。適切な長期的な選択は、ホイールを再発明する代わりに、そのようなフレームワークを活用することです。
次のコードは、短期的な解決策です。これはあなたの質問で言及した特定のケースを解決するかもしれませんが、オブジェクトマッピングには多くのコーナーケースがあり、最終的に別のコーディングケースに遭遇します。 AutoMapperや同様のフレームワークを使用するように移行するまで、これを一時的な修正としてのみ使用することをお勧めします。問題はBuddy
プロパティは、他のすべてとは違って、モデルとDTOに異なる種類を持っていることである
static void Main(string[] args)
{
var user = new UserModel
{
Name = "User McUserson",
Age = 30,
Buddy = new UserModel
{
Name = "Buddy McFriendly",
Age = 28
}
};
// This fails saying that UserModel cannot be converted to UserDto
var userDto = Cast<UserDto>(user);
}
class UserModel
{
public String Name { get; set; }
public int Age { get; set; }
public UserModel Buddy { get; set; }
}
class UserDto
{
public String Name { get; set; }
public int Age { get; set; }
public UserDto Buddy { get; set; }
}
:あなたの説明とあなたのコードに基づいて
は、こちらのモデルあなたの失敗例です。クラス。 UserModel
は単にUserDto
に割り当てられません。唯一の例外は、値がnullの場合です。
クラスタイプのプロパティの場合、ターゲットをソースと同じにする代わりに、ソースタイプをターゲットタイプにマッピングする必要があります。UserModel - > UserDto。これは、再帰呼び出しで行うことができます。
この問題を解決するコードを表示する前に、1分間の名前付けについて説明します。あなたの関数Cast()を呼び出すことは非常に誤解を招きます。ここで実際に行っている操作は、ある種のソースオブジェクトを取得し、そのプロパティ値を特定のタイプのターゲットオブジェクトにマッピングすることです(クラスタイプのプロパティの再帰的マッピングが可能です)。別に
static void Main(string[] args)
{
var user = new UserModel
{
Name = "User McUserson",
Age = 30,
Buddy = new UserModel
{
Name = "Buddy McFriendly",
Age = 28
}
};
// This works!
var userDto = MapProperties<UserDto>(user);
}
:
public static T MapProperties<T>(object source)
{
return (T)MapProperties(source, typeof(T));
}
public static object MapProperties(object source, Type targetType)
{
object target = Activator.CreateInstance(targetType, nonPublic: false);
Type sourceType = source.GetType();
var sourcePropertyLookup = sourceType.GetProperties().ToDictionary(p => p.Name);
var targetPropertyLookup = targetType.GetProperties().ToDictionary(p => p.Name);
var commonProperties = targetPropertyLookup.Keys.Intersect(sourcePropertyLookup.Keys);
foreach (var commonProp in commonProperties)
{
PropertyInfo sourceProp = sourcePropertyLookup[commonProp];
PropertyInfo targetProp = targetPropertyLookup[commonProp];
object sourcePropValue = sourceProp.GetValue(source);
if(sourcePropValue == null || targetProp.PropertyType.IsAssignableFrom(sourceProp.PropertyType))
{
targetProp.SetValue(target, sourceProp.GetValue(source));
}
else
{
object mappedValue = MapProperties(sourceProp.GetValue(source), targetProp.PropertyType);
targetProp.SetValue(target, mappedValue);
}
}
return target;
}
はあなたがあなたの前のコードを使用していたのと同じ方法でこれを使用することができます。この用語を考えると
は
、ここでは、この特定の問題を解決し、いくつかの更新されたコードですいくつかの最適化から、コードとの重要な違いはif-elseブロックにあります。ソース値を直接ターゲットに割り当てることができるかどうかを確認します。その場合、コードはこれまでの処理を行います。それ以外の場合は、値を再帰的にマップする必要があると想定します。この新しいセクションでは、モデルクラス型のソースプロパティをDTOクラス型のターゲットプロパティに変換する問題を解決します。
なぜあなたはそれを行いますか?代わりにAutoMapperや同様のフレームワークを使用してください。 –
@HristoYankov、私のデータベースはNHibernateを使ってマップしています。これはちょうど私のモデルクラスを私のDTOに変換することができます。 –
正確に私のポイント、はい。 –