2016-11-19 9 views
0

私は現在、私が作った方法にいくつかの問題があります。私はリフレクションを使用してクラスを実行し、すべてのプロパティを取得します。これを使用してモデルをDTOにキャストしたり、その逆もあります。サブクラスの反射型エラー

私が遭遇している問題は、クラスが属性として別のクラスを持っているときはいつもエラーが出ます。

タイプ 'UserTypeProxy'のオブジェクトは、タイプ「MyNamespace.DTO.UserTypeDto」に変換できません。

これは私のコードです:以前のコメンター状態として

public static T Cast<T>(object myobj) 
{ 
    Type _objectType = myobj.GetType(); 
    Type target = typeof(T); 

    var x = Activator.CreateInstance(target, false); 

    var z = from source in _objectType.GetMembers().ToList() 
      where source.MemberType == MemberTypes.Property 
      select source; 

    var d = from source in target.GetMembers().ToList() 
      where source.MemberType == MemberTypes.Property 
      select source; 

    List<MemberInfo> members = d.Where(memberInfo => d.Select(c => c.Name) 
     .ToList().Contains(memberInfo.Name)).ToList(); 

    PropertyInfo propertyInfo; 
    object value; 

    foreach (var memberInfo in members) 
    { 
     propertyInfo = typeof(T).GetProperty(memberInfo.Name); 
     var propy = myobj.GetType().GetProperty(memberInfo.Name); 
     value = propy.GetValue(myobj, null); 

     propertyInfo.SetValue(x, value, null); //<-- this is the line that gives the error 
    } 
    return (T)x; 
} 
+0

なぜあなたはそれを行いますか?代わりにAutoMapperや同様のフレームワークを使用してください。 –

+0

@HristoYankov、私のデータベースはNHibernateを使ってマップしています。これはちょうど私のモデルクラスを私のDTOに変換することができます。 –

+0

正確に私のポイント、はい。 –

答えて

1

、これはあなたが自分自身を維持/書き込みする必要があるコードのようなものではありません。 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クラス型のターゲットプロパティに変換する問題を解決します。

+0

ありがとうございました。私はオートマッパーを見ます –