Est-il possible de déclarer un type anonyme en C # avec un ensemble variable / dynamique de champs?

anonymous-types c# dapper dynamic

Question

En C #, j'aimerais savoir s'il est possible de déclarer un type anonyme dont les champs ne sont connus qu'au moment de l'exécution.

Par exemple, si j'ai une liste de paires clé / valeur, puis-je déclarer un type anonyme en fonction du contenu de cette liste? Le cas spécifique avec lequel je travaille consiste à transmettre des paramètres à Dapper, où je ne sais pas à l'avance combien de paramètres j'aurai.

List<Tuple<string, string>> paramList = new List<Tuple<string, string>>() {
    new Tuple<string, string>("key1", "value1"),
    new Tuple<string, string>("key2", "value2")
    ...
};

Je voudrais convertir cette liste (ou une carte équivalente) en un type anonyme que je peux transmettre à Dapper en tant que paramètres de requête. Donc, idéalement, la liste ci-dessus finirait par ressembler à ceci, si elle est définie comme un type anonyme:

new { key1=value1, key2=value2, ... }

J'ai vu plusieurs questions sur StackOverflow demandant comment étendre les types anonymes après leur déclaration ("objets extendo"), ou déclarer des champs arbitraires sur un objet après sa création, mais je n'ai pas besoin de le faire ... déclarer les types de manière dynamique une fois. Mon soupçon est que cela nécessitera une réflexion fantaisiste, si possible.

Ma compréhension est que le compilateur définit un type pour les classes anonymes sous le capot au moment de la compilation, donc si les champs de cette classe ne sont pas disponibles avant l'exécution, je risque de ne pas avoir de chance. Mon cas d'utilisation ne peut en réalité pas être différent en utilisant un "objet extendo" pour définir des champs arbitraires, à chaque fois.

Sinon, si quelqu'un connaît un meilleur moyen de transmettre les paramètres de requête à Dapper (plutôt que de déclarer une classe anonyme), j'aimerais aussi en entendre parler.

Merci!

METTRE À JOUR

Désolé pour le retard à revenir à celui-ci! Ces réponses étaient toutes excellentes, je voudrais pouvoir donner des points à tout le monde. J'ai fini par utiliser la solution de jbtule (avec l'édition de Sam Saffron), en passant IDynamicParameters à Dapper, alors j'ai senti que je devais lui donner la réponse. Les autres réponses étaient également bonnes et répondaient à des questions spécifiques que j'avais posées. J'apprécie vraiment le temps de chacun pour ça!

Réponse acceptée

Les créateurs de Dapper étaient très conscients de ce problème. Ce type de fonctionnalité est vraiment nécessaire pour les assistants INSERT et UPDATE .

Les méthodes Query , Execute et QueryMultiple prennent un paramètre dynamic . Cela peut être un type anonyme, un type concret ou un objet qui implémente IDynamicParameters .

public interface IDynamicParameters
{
    void AddParameters(IDbCommand command, Identity identity);
}

Cette interface est très pratique, AddParameters est appelée juste avant d'exécuter un SQL. Non seulement cela vous donne un contrôle riche sur les paramètres envoyés à SQL. Il vous permet de raccorder des paramètres DbParameters spécifiques à la base de données, puisque vous avez accès à la commande (vous pouvez la convertir en celle spécifique à la base de données). Cela permet de prendre en charge les paramètres de valeurs de tableau, etc.

Dapper contient une implémentation de cette interface qui peut être utilisée pour vos besoins appelés DynamicParameters . Cela vous permet de concaténer des sacs de paramètres anonymes et d'ajouter des valeurs spécifiques.

Vous pouvez utiliser la méthode AddDynamicParams pour ajouter un type anonyme.

var p = new DynamicParameters();
p.AddDynamicParams(new{a = "1"});
p.AddDynamicParams(new{b = "2", c = "3"});
p.Add("d", "4")
var r = cnn.Query("select @a a, @b b, @c c, @d d", p);
// r.a == 1, r.b == 2, r.c == 3, r.d == 4

Réponse populaire

En C #, j'aimerais savoir s'il est possible de déclarer un type anonyme dont les champs ne sont connus qu'au moment de l'exécution.

Les types anonymes sont générés par le compilateur. Vous voulez savoir si le compilateur va vous générer un type généré par le compilateur avec des types de champs inconnus du compilateur . De toute évidence, il ne peut pas le faire; comme vous le supposez correctement, vous n'avez pas de chance.

J'ai vu plusieurs questions sur StackOverflow demandant des extensions de types anonymes après leur déclaration ("objets extendo")

Nous appelons généralement ces objets "expando".

Si vous voulez faire un objet expando basé sur un dictionnaire de paires clé-valeur, utilisez la classe ExpandoObject pour le faire. Voir cet article MSDN pour plus de détails:

http://msdn.microsoft.com/en-us/magazine/ff796227.aspx

Si vous voulez générer une classe .NET authentique lors de l'exécution, vous pouvez le faire aussi. Comme vous le remarquez correctement, vous avez besoin de quelques réflexions pour le faire. Ce que vous voulez faire, c'est créer un assemblage à collectionner (ainsi appelé, car contrairement à un assemblage normal, vous le générez à l'exécution et le ramasse-miettes le nettoie lorsque vous en avez fini avec).

Voir http://msdn.microsoft.com/en-us/library/dd554932.aspx pour plus de détails sur la création d'un assemblage à collectionner et son émission à l'aide d'un TypeBuilder.




Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi