Quelle est la meilleure façon de fusionner deux objets lors de l'exécution en utilisant C #?

StackOverflow https://stackoverflow.com/questions/1358877

  •  20-09-2019
  •  | 
  •  

Question

J'ai deux objets et je veux les fusionner:

public class Foo
{
    public string Name { get; set; }
}

public class Bar
{
    public Guid Id { get; set; }
    public string Property1 { get; set; }
    public string Property2 { get; set; }
    public string Property3 { get; set; }
    public string Property4 { get; set; }
}

Pour créer:

public class FooBar
{
    public string Name { get; set; }
    public Guid Id { get; set; }
    public string Property1 { get; set; }
    public string Property2 { get; set; }
    public string Property3 { get; set; }
    public string Property4 { get; set; }
}

Je ne connaître la structure de Foo lors de l'exécution. Bar peut être tout type lors de l'exécution. Je voudrais avoir une méthode qui sera donnée un type et combiner ce type avec Foo. Par exemple, le scénario ci-dessus, la méthode a été donné un type barre à l'exécution et je combiné avec Foo.

Quelle serait la meilleure façon de le faire? Peut-il être fait en utilisant des expressions LINQ ou dois-je générer ou est-il Dynamiquement une autre façon? Je continue à apprendre le nouvel espace de noms LINQ en C # 3.0, excuse l'ignorance si elle ne peut être fait en utilisant des expressions LINQ. Ceci est aussi la première fois que je devais faire quelque chose de dynamique comme celui-ci avec C #, donc je ne suis pas tout à fait sûr de toutes les options dont je dispose pour moi.

Merci pour toutes les options disponibles.

EDIT


Il est strictement pour ajouter des méta-informations du type qui m'a été donnée pour la sérialisation. Ce scénario conserve les objets de l'utilisateur ignorant des méta-informations qui doit être ajouté, avant qu'il ne soit publié en feuilleton. Je suis venu avec deux options avant de poser cette question et je voulais juste voir s'il y avait plus, avant de décider lequel utiliser.

Les deux options que je suis venu avec sont:

la chaîne sérialisée Manipuler du type qui m'a été donné après la sérialisation il, en ajoutant les méta-informations.

Emballage du type donné à moi, ce qui est semblable à ce que @Zxpro mentionné, mais la mienne était légèrement différente, ce qui est bien. Il va juste faire l'utilisateur de mon API doivent suivre la convention, ce qui est une mauvaise chose, puisque tout le monde est sur le point sur la configuration convention:

public class Foo<T>
{
    public string Name { get; set; }
    public T Content { get; set; }
}

EDIT


Merci tout le monde pour leurs réponses. J'ai décidé envelopper l'objet comme ci-dessus et j'ai donné la réponse à @Zxpro, étant donné que la majorité aimait cette approche également.

Si quelqu'un d'autre vient à travers cette question, ne hésitez pas à poster, si vous pensez qu'il pourrait y avoir une meilleure façon.

Était-ce utile?

La solution

Si vous ne les dérange pas d'être regroupés plutôt que fusionné :

public class FooEx<T>
{
    public Foo Foo { get; set; }
    public T Ex { get; set; }
}

Autres conseils

NON TESTÉ, mais en utilisant l'API Reflection.Emit, quelque chose comme cela devrait fonctionner:

public Type MergeTypes(params Type[] types)
{
    AppDomain domain = AppDomain.CurrentDomain;
    AssemblyBuilder builder = 
        domain.DefineDynamicAssembly(new AssemblyName("CombinedAssembly"),
        AssemblyBuilderAccess.RunAndSave);
    ModuleBuilder moduleBuilder = builder.DefineDynamicModule("DynamicModule");
    TypeBuilder typeBuilder = moduleBuilder.DefineType("CombinedType");
    foreach (var type in types)
    {
        var props = GetProperties(type);
        foreach (var prop in props)
        {
            typeBuilder.DefineField(prop.Key, prop.Value, FieldAttributes.Public);
        }
    }

    return typeBuilder.CreateType();


}

private Dictionary<string, Type> GetProperties(Type type)
{
    return type.GetProperties().ToDictionary(p => p.Name, p => p.PropertyType);
}

Utilisation:

Type combinedType = MergeTypes(typeof(Foo), typeof(Bar));

Malheureusement, ce n'est pas quelque chose que vous pouvez faire facilement. Le mieux que vous pouvez faire est de créer un type anonyme dans le cadre d'une requête LINQ, mais qui aura locale portée uniquement, et donc ne sera bon pour vous dans la méthode dans laquelle vous faites.

Lorsque .NET 4 sort, il y a une nouvelle bibliothèque dynamique d'exécution qui pourraient vous aider.

En dehors de la question « Pourquoi », la seule façon que je peux penser à prendre deux objets, l'un connu et un inconnu, et les combiner en un nouveau type serait d'utiliser Reflection.Emit pour générer un nouveau type à l'exécution.

Il existe des exemples sur MSDN. Vous devez déterminer la météo que vous vouliez des champs de fusion qui avait le même nom ou dont le type connu remplace le type inconnu.

Pour autant que je peux dire, il n'y a aucun moyen de le faire dans LINQ.

Depuis tout ce que vous êtes intéressé est Propriétés il devrait être assez facile à utiliser cette article comme exemple. Laissez le il pour créer des méthodes et vous êtes bon pour aller.

Comme d'autres l'ont souligné, il n'y a aucun moyen de « fusionner » les (si vous envisagez d'un select * avec plusieurs tables dans SQL, par exemple). Votre analogique le plus proche serait de prendre la route que Zxpro a fourni et les « groupe » dans une classe générique.

Qu'est-ce, exactement, vous voulez accomplir avec « fusion » eux, bien? Déclarant les propriétés serait explicitement que le plus grand effet pratique sur le code d'écriture et de compilation sécurité, mais si vous ne pouvez pas spécifier un type alors il n'y a aucune possibilité pour cela. Si vous êtes à la recherche d'un générique conteneur « sac de propriété », puis une structure de données existantes, comme un Dictionary<T,T> ou Hashtable doit être capable de gérer cela.

Si vous pouvez ajouter une méthode à la classe de métadonnées que vous pouvez faire quelque chose comme ce qui suit

public class Foo
{
    public string Name { get; set; }
    public void SerializeWithMetadata(Bar bar)
    {
       var obj = new {
                       Name = this.Name,
                       Guid = bar.Guid,
                       Property1 = Bar.Property1
                      }
       //Serialization code goes here
    }
}

public class Bar
{
    public Guid Id { get; set; }
    public string Property1 { get; set; }
    public string Property2 { get; set; }
    public string Property3 { get; set; }
    public string Property4 { get; set; }
}

Je ne suis pas sûr que je recommande cette approche exacte j'ai surtout laissé ici pour afficher des types anonymes comme une option possible qui pourrait être la peine d'explorer

Une autre option:

Modifier la première classe comme si

public class Foo
{
    public string Name { get; set; }

    [System.Xml.Serialization.XmlAnyElementAttribute()]
    public XmlElement Any {get;set;}
}

Prenez la deuxième classe et sérialisation en un XmlElement comme ceci:

XmlElement SerializeToElement(Type t, object obj)
{
    XmlSerializer ser = new XmlSerializer(t);
    StringWriter sw = new StringWriter();
    using (XmlWriter writer = XmlWriter.Create(sw, settings))
        ser.Serialize(writer, obj);

    string val  = sw.ToString();

    XmlDocument doc = new XmlDocument();
    doc.LoadXml(xmlString);

    return (XmlElement)doc.DocumentElement;

}

Définir la propriété Tout au XmlElement et sérialiser Vous verrez le XML pour l'autre classe embarquée dans le document, avec tous les espaces de noms

Vous pouvez même obtenir avec si la classe a été générée à l'aide Xsd.exe si vous utilisez ce qui suit comme un élément:

<xs:any namespace="##any" processContents="lax" />

Je crois que vous pouvez vous en sortir avec un tableau de XmlElements pour plus d'une sous-classe.

Deserializaing devrait être une question de l'inspection des XmlElements et alors à la recherche d'une classe correspondant, ou peut-être en utilisant l'espace de noms pour trouver la classe.

Ceci est beaucoup plus net que vous embêter avec la manipulation de chaînes.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top