web-dev-qa-db-fra.com

classe de cast dans une autre classe ou convertir la classe à une autre

ma question est montrée dans ce code 

J'ai cours comme ça 

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;    
}
29
Khalid Omar

Ce qu'il veut dire, c'est: 

"Si vous avez deux classes partageant la plupart des mêmes propriétés, vous pouvez convertir un objet de la classe a en classe b et faire en sorte que le système comprenne l'affectation via les noms de propriétés partagées?"

Option 1: utiliser la réflexion 

Inconvénient: ça va te ralentir plus que tu ne le penses.

Option 2: Faites en sorte qu'une classe dérive d'une autre, la première ayant des propriétés communes et l'autre une extension de celle-ci.

Inconvénient: couplé! si vous faites cela pour deux couches dans votre application, les deux couches seront couplées!

Qu'il y ait:

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

Maintenant, voici une extension pour le type d'objet:

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

Maintenant, vous l'utilisez comme ceci:

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

La méthode cast vérifie les propriétés communes entre deux objets et effectue l'affectation automatiquement.

29
Stacker

Vous avez déjà défini la conversion, il vous suffit de faire un pas de plus si vous souhaitez pouvoir effectuer un casting. Par exemple: 

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

Ce qui vous permet ensuite de faire quelque chose comme 

static void Main()
{
    sub1 mySub = new sub1();
    maincs myMain = (maincs)mySub;
}
51
Anthony Pegram

Utilisez la sérialisation et la désérialisation JSON:

using Newtonsoft.Json;

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

Ou:

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

Ce qui vous permet ensuite de faire quelque chose comme

static void Main()
{
    Class1 obj1 = new Class1();
    Class2 obj2 = (Class2)obj1;
}
27
Tyler Long

Vous pouvez modifier la structure de votre classe pour:

public class maincs : sub1
{
   public int d; 
}

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

Ensuite, vous pourriez garder une liste de sub1 et en envoyer certains à mainc.

5
Jake Pearson

Vous pouvez fournir une surcharge explicite à l'opérateur de conversion:

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

Une autre option consisterait à utiliser une interface possédant les propriétés a, b et c et à implémenter l'interface sur les deux classes. Ensuite, il suffit que le type de paramètre à methoda soit l'interface au lieu de la classe.

2
Chris Shaffer

En utilisant ce code, vous pouvez copier n'importe quel objet de classe dans un autre objet de classe avec le même nom et le même type de propriétés.

JavaScriptSerializer JsonConvert = new JavaScriptSerializer(); 
string serializeString = JsonConvert.Serialize(objectEntity);
objectViewModel objVM = JsonConvert.Deserialize<objectViewModel>(serializeString);
1
Yats_Bhavsar

En utilisant le code suivant, vous pouvez copier tout objet de classe dans un autre objet de classe pour le même nom et le même type de propriétés.

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

Méthode d'appel

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

CopyClass.CopyObject(objOfferMast, ref objB);

Il va copier objA dans objB.

1
Kailas Mane

Il y a quelques bonnes réponses ici, je voulais juste ajouter un peu de vérification de type ici car nous ne pouvons pas supposer que si des propriétés portent le même nom, elles sont du même type. Voici mon offre, qui s'étend sur la précédente, très excellente réponse car j'avais quelques petits problèmes avec elle.

Dans cette version, j'ai permis au consommateur de spécifier les champs à exclure et également, par défaut, d'exclure toute propriété associée à une base de données ou à un modèle.

    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;
    }
1
SpaceKat
var obj =  _account.Retrieve(Email, hash);

AccountInfoResponse accountInfoResponse = new AccountInfoResponse();

if (obj != null)
{               
   accountInfoResponse = 
   JsonConvert.
   DeserializeObject<AccountInfoResponse>
   (JsonConvert.SerializeObject(obj));
}

description de l'image