2016-11-19 2 views
0

Ich habe derzeit einige Probleme mit einer Methode, die ich gemacht habe. Ich benutze Reflektion, um meine Klasse zu durchlaufen und alle Eigenschaften zu erhalten. Ich benutze dies, um meine Modelle in DTO zu verwandeln und umgekehrt.Unterklasse Reflection type error

Das Problem, das mir begegnet, ist, dass, wenn meine Klasse eine andere Klasse als Attribut hat, bekomme ich einen Fehler.

Objekt vom Typ 'UserTypeProxy' kann nicht in den Typ 'MyNamespace.DTO.UserTypeDto' konvertiert werden.

Dies ist mein Code:

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

Warum würden Sie das tun ??? Verwenden Sie stattdessen AutoMapper oder ein ähnliches Framework. –

+0

@HristoYankov, für meine Datenbank verwende ich NHibernate zum Zuordnen. Dies ist nur so, dass ich meine Model-Klassen in mein DTO konvertieren kann. –

+0

Genau mein Punkt, ja. –

Antwort

1

Als vorherigen Kommentator Staaten, dies nicht die Art von Code ist es, Sie zu schreiben sollten/selbst zu halten. Frameworks wie AutoMapper wurden speziell entwickelt, um das Problem zu lösen, das Sie angreifen - das Konvertieren von Modellobjekten in DTOs. Die richtige langfristige Entscheidung wäre, einen solchen Rahmen zu nutzen, anstatt das Rad neu zu erfinden.

In der Zwischenzeit ist der folgende Code eine kurzfristige Lösung für Ihr Problem. Denken Sie daran, dass, während dies den spezifischen Fall lösen kann, den Sie in Ihrer Frage erwähnen, das Objekt-Mapping viele Fälle hat und Sie schließlich in einen anderen geraten werden. Ich würde empfehlen, dies nur als vorübergehende Lösung zu verwenden, bis Sie zur Verwendung von AutoMapper oder eines ähnlichen Frameworks migrieren.

Basierend auf Ihrer Beschreibung und Ihren Code, hier ist ein Beispiel, das Modell Ihres Versagen:

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; } 
} 

Das Problem ist, dass die Buddy Eigenschaft, im Gegensatz zu allen anderen, eine anderen Art im Modell hat und DTO Klassen. Eine UserModel ist einfach nicht einer UserDto zuweisbar. Die einzige Ausnahme ist, wenn der Wert null ist.

Bei Eigenschaften, bei denen es sich um Klassentypen handelt, müssen Sie den Quellentyp nicht dem Zieltyp, sondern dem Zieltyp zuordnen: UserModel -> UserDto. Dies kann mit einem rekursiven Aufruf erfolgen.

Bevor ich Ihnen den Code zeige, der dieses Problem löst, sprechen wir über die Benennung für eine Minute. Aufruf der Funktion Cast() ist sehr irreführend. Die Operation, die wir hier wirklich ausführen, nimmt ein Quellobjekt und weist seine Eigenschaftswerte auf ein Zielobjekt eines bestimmten Typs zu (mit möglichen rekursiven Zuordnungen für Eigenschaften, die Klassentypen sind).

diese Terminologie gegeben, hier einige aktualisierte Code, der dieses spezielle Problem löst:

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; 
} 

Sie können Sie diese auf die gleiche Weise verwenden haben Ihre vorherigen Code verwendet:

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); 
} 

Abgesehen Von einigen Optimierungen unterscheiden sich die wichtigsten Unterschiede zu Ihrem Code im if-else-Block. Dort überprüfen wir, ob wir den Quellwert direkt dem Ziel zuweisen können. In diesem Fall tun wir, was Ihr Code bisher getan hat. Andernfalls wird angenommen, dass wir den Wert rekursiv zuordnen müssen. Dieser neue Abschnitt löst das Problem der Konvertierung einer Quelleigenschaft eines Modellklassentyps in eine Zieleigenschaft eines DTO-Klassentyps.

+0

Vielen Dank. Ich werde in Auto Mapper schauen –

Verwandte Themen