2010-09-08 13 views
20

meine Frage istGuss Klasse in eine andere Klasse oder konvertieren Klasse in eine andere

in diesem Code gezeigt

Ich habe Klasse, wie die

public class maincs 
{ 
    public int a; 
    public int b; 
    public int c; 
    public int d; 
} 

public class sub1 
{ 
    public int a; 
    public int b; 
    public int c; 
} 


public void methoda (sub1 model) 
{ 
    maincs mdata = new maincs(){a = model.a , b = model.b , c= model.c} ; 

    // is there is a way to directly cast class sub1 into main like that  
    mdata = (maincs) model;  
} 
+1

Dieser Code macht keinen Sinn. Postcode, der kompiliert (es ist nicht die Besetzung, die das Problem ist). –

+7

Ziemlich hart .. Das Fehlen eines 'class' Schlüsselworts nimmt den Sinn nicht weg. – nawfal

+0

Es gibt bereits existierende Lightweight-Mapper-Bibliotheken, die für genau diesen Zweck geschrieben wurden. Sie behandeln viel mehr Randfälle. Sie können es googeln. – nawfal

Antwort

23

Was er sagen will, ist:

„Wenn Sie zwei Klassen haben, die meisten die gleichen Eigenschaften teilen können Sie ein Objekt aus der Klasse a Klasse werfen b und automatisch das System verstehen, die Zuordnung über den gemeinsamen Eigenschaftsnamen? "

Option 1: Verwenden Reflexion

Nachteil: Es wird Sie gonna mehr verlangsamen, als Sie denken.

Option 2: Machen Sie eine Klasse von einer anderen ableiten, die erste mit gemeinsamen Eigenschaften und andere eine Erweiterung davon.

Nachteil: Gekoppelt! Wenn Sie das für zwei Schichten in Ihrer Anwendung tun, werden die beiden Schichten gekoppelt!

Es werde:

class customer 
{ 
    public string firstname { get; set; } 
    public string lastname { get; set; } 
    public int age { get; set; } 
} 
class employee 
{ 
    public string firstname { get; set; } 
    public int age { get; set; } 
} 

hier Jetzt ist eine Erweiterung für Objekttyp:

public static T Cast<T>(this 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); 
     value = myobj.GetType().GetProperty(memberInfo.Name).GetValue(myobj,null); 

     propertyInfo.SetValue(x,value,null); 
    } 
    return (T)x; 
} 

Jetzt verwenden Sie es wie folgt aus:

static void Main(string[] args) 
{ 
    var cus = new customer(); 
    cus.firstname = "John"; 
    cus.age = 3; 
    employee emp = cus.Cast<employee>(); 
} 

Gussverfahren prüft gemeinsame Eigenschaften zwischen zwei Objekten und führt die Zuweisung automatisch durch.

+1

Das, was ich meine genau –

+0

Schöne Lösung, aber wie Sie gesagt haben, Overhead und Komplexität :) – Noctis

+0

Ich denke, Sie haben es versäumt, 'z' Variable zu verwenden. Es sollte verwendet werden, wenn 'Mitglieder' initialisiert werden var ie Liste members = z.Where (memberInfo => d.Select (c => c.Name) .ToList(). Enthält (memberInfo.Name)). ToList() ; – Aamol

5

Sie Ihre Klassenstruktur verändern könnte:

public class maincs : sub1 
{ 
    public int d; 
} 

public class sub1 
{ 
    public int a; 
    public int b; 
    public int c; 
} 

Dann könnten Sie eine Liste von Sub1 behalten und einige von ihnen zu Mainc werfen.

+0

Dies kompiliert auch nicht. Vielleicht haben Sie das 'class' Schlüsselwort vergessen –

+0

Hoppla, das bekomme ich zum Kopieren/Einfügen. –

43

Sie haben die Konvertierung bereits definiert, Sie müssen nur noch einen Schritt weiter gehen, wenn Sie in der Lage sein möchten zu können. Zum Beispiel:

public class sub1 
{ 
    public int a; 
    public int b; 
    public int c; 

    public static explicit operator maincs(sub1 obj) 
    { 
     maincs output = new maincs() { a = obj.a, b = obj.b, c = obj.c }; 
     return output; 
    } 
} 

die dann Sie so etwas wie

static void Main() 
{ 
    sub1 mySub = new sub1(); 
    maincs myMain = (maincs)mySub; 
} 
+2

Noch besser als die ausgewählte Antwort – Noctis

+1

Große Antwort. Vielen Dank. – Ellis

+0

Gibt es irgendwelche Auswirkungen auf das Konvertieren/Casting von einer Klasse in eine andere mit den genauen Requisiten mit Ihrem Code? – Code

2

Sie können eine explizite Überlastung sorgen für die Cast-Operator erlaubt, zu tun:

public static explicit operator maincs(sub1 val) 
{ 
    var ret = new maincs() { a = val.a, b = val.b, c = val.c }; 
    return ret; 
} 

Eine andere Möglichkeit wäre, ein verwenden Schnittstelle, die die Eigenschaften a, b und c aufweist und die Schnittstelle für beide Klassen implementiert. Dann muss der Parameter type zu methoda die Schnittstelle anstelle der Klasse sein.

1

Mit dem folgenden Code können Sie ein beliebiges Klassenobjekt in ein anderes Klassenobjekt für denselben Namen und denselben Typ von Eigenschaften kopieren.

public class CopyClass 
{ 
    /// <summary> 
    /// Copy an object to destination object, only matching fields will be copied 
    /// </summary> 
    /// <typeparam name="T"></typeparam> 
    /// <param name="sourceObject">An object with matching fields of the destination object</param> 
    /// <param name="destObject">Destination object, must already be created</param> 
    public static void CopyObject<T>(object sourceObject, ref T destObject) 
    { 
     // If either the source, or destination is null, return 
     if (sourceObject == null || destObject == null) 
      return; 

     // Get the type of each object 
     Type sourceType = sourceObject.GetType(); 
     Type targetType = destObject.GetType(); 

     // Loop through the source properties 
     foreach (PropertyInfo p in sourceType.GetProperties()) 
     { 
      // Get the matching property in the destination object 
      PropertyInfo targetObj = targetType.GetProperty(p.Name); 
      // If there is none, skip 
      if (targetObj == null) 
       continue; 

      // Set the value in the destination 
      targetObj.SetValue(destObject, p.GetValue(sourceObject, null), null); 
     } 
    } 
} 

Call-Methode Wie,

ClassA objA = new ClassA(); 
ClassB objB = new ClassB(); 

CopyClass.CopyObject(objOfferMast, ref objB); 

Es wird objA in objB kopieren.

+1

Bitte beachten Sie, dass bei Verwendung dieser Lösung möglicherweise Probleme auftreten, wenn Klassen denselben Namen für Eigenschaften, jedoch unterschiedliche Typen haben. Zum Beispiel: 'öffentliche Klasse A {public int Age {get; set;}}} und öffentliche Klasse B {public string Age {get; set;}}' ' Wird eine Ausnahme auslösen, wenn Sie versuchen zu konvertieren von "A" bis "B" – Noctis

+0

Diese Art der Konvertierung könnte auch zu einigen großen Leistungsproblemen führen. Verwenden Sie es vorsichtig und sicherlich nicht in for-Schleifen – RPDeshaies

11

Eine weitere Option ist Json Serialisierung und Deserialisierung zu verwenden:

using Newtonsoft.Json; 

Class1 obj1 = new Class1(); 
Class2 obj2 = JsonConvert.DeserializeObject<Class2>(JsonConvert.SerializeObject(obj1)); 

Oder:

public class Class1 
{ 
    public static explicit operator Class2(Class1 obj) 
    { 
     return JsonConvert.DeserializeObject<Class2>(JsonConvert.SerializeObject(obj)); 
    } 
} 

die dann können Sie etwas tun, wie

static void Main() 
{ 
    Class1 obj1 = new Class1(); 
    Class2 obj2 = (Class2)obj1; 
} 
+1

Ja, mit Newtonsoft json Serializer ist ziemlich einfach und effizient. Es gibt. Net Serializer, aber ich fand Newtonsoft gut über. Net Json Serializer. Ich fand diesen Link, der einen kurzen Vergleich gibt http://www.newtonsoft.com/json/help/html/JsonNetVsDotNetSerializers.htm – Aamol

1

Es gibt einige gute Antworten hier, ich wollte nur hier ein wenig Typprüfung hinzufügen, da wir nicht davon ausgehen können, dass wenn Eigenschaften mit demselben Namen existieren, sie vom selben Typ sind. Hier ist mein Angebot, das sich auf die vorherige, sehr gute Antwort erstreckt, da ich ein paar kleine Pannen damit hatte.

In dieser Version habe ich zugelassen, dass der Benutzer Felder angibt, die ausgeschlossen werden sollen, und standardmäßig auch alle datenbank-/modellspezifischen Eigenschaften ausschließt.

public static T Transform<T>(this object myobj, string excludeFields = null) 
    { 
     // Compose a list of unwanted members 
     if (string.IsNullOrWhiteSpace(excludeFields)) 
      excludeFields = string.Empty; 
     excludeFields = !string.IsNullOrEmpty(excludeFields) ? excludeFields + "," : excludeFields; 
     excludeFields += $"{nameof(DBTable.ID)},{nameof(DBTable.InstanceID)},{nameof(AuditableBase.CreatedBy)},{nameof(AuditableBase.CreatedByID)},{nameof(AuditableBase.CreatedOn)}"; 

     var objectType = myobj.GetType(); 
     var targetType = typeof(T); 
     var targetInstance = Activator.CreateInstance(targetType, false); 

     // Find common members by name 
     var sourceMembers = from source in objectType.GetMembers().ToList() 
            where source.MemberType == MemberTypes.Property 
            select source; 
     var targetMembers = from source in targetType.GetMembers().ToList() 
            where source.MemberType == MemberTypes.Property 
            select source; 
     var commonMembers = targetMembers.Where(memberInfo => sourceMembers.Select(c => c.Name) 
      .ToList().Contains(memberInfo.Name)).ToList(); 

     // Remove unwanted members 
     commonMembers.RemoveWhere(x => x.Name.InList(excludeFields)); 

     foreach (var memberInfo in commonMembers) 
     { 
      if (!((PropertyInfo)memberInfo).CanWrite) continue; 

      var targetProperty = typeof(T).GetProperty(memberInfo.Name); 
      if (targetProperty == null) continue; 

      var sourceProperty = myobj.GetType().GetProperty(memberInfo.Name); 
      if (sourceProperty == null) continue; 

      // Check source and target types are the same 
      if (sourceProperty.PropertyType.Name != targetProperty.PropertyType.Name) continue; 

      var value = myobj.GetType().GetProperty(memberInfo.Name)?.GetValue(myobj, null); 
      if (value == null) continue; 

      // Set the value 
      targetProperty.SetValue(targetInstance, value, null); 
     } 
     return (T)targetInstance; 
    } 
Verwandte Themen