Dapper: Quelle est la différence entre ces deux morceaux de code?

c# dapper

Question

J'ai enregistré un gestionnaire de type personnalisé pour Dapper à Json sérialiser une chaîne. Cela fonctionne comme prévu. Cependant, lors du codage, j'ai découvert deux morceaux de code après le refactoring, le dernier n'ayant pas déclenché le gestionnaire de types de données, mais à mon avis, quelle est la différence?

D'abord, le code qui fonctionne comme prévu - le gestionnaire de type personnalisé est appelé par dapper et les données sont sérialisées lorsqu'elles sont insérées dans la table:

if (val.GetType() != typeof (String))
{
    var v = new JsonString {Value = val};
    this.Connection.Execute("insert into misc (k,v) values (@keyName, @v)", 
        new { keyName, v });
}
else
{
    this.Connection.Execute("insert into misc (k,v) values (@keyName, @val)", 
        new { keyName, val });
}

Maintenant, pour le code qui ne fonctionne pas, il insère dans la table la chaîne de caractères pleinement qualifiée au lieu des données sérialisées, mais je pense que c'est sémantiquement similaire:

var v = val.GetType() != typeof (String)
        ? new JsonString {Value = val}
        : val;

// t is set to type of JsonString, therefore the dapper type handler should be used
var t = v.GetType();

this.Connection.Execute("insert into misc (k,v) values (@keyName, @v)", 
    new { keyName, v });

Est-ce un bug ou une bizarrerie? Je suppose que cela a quelque chose à voir avec la saisie automatique dans le conditionnel ternaire qui est le point d'échec, mais t est défini sur le type de données sérialisé par Dapper (ou plutôt le gestionnaire de type personnalisé). Quelle est la différence?

Réponse acceptée

Je vais supposer que le type de compilation (c'est-à-dire le type de déclaration) de val est System.Object . Je vais expliquer pourquoi les deux situations ne sont pas équivalentes.

Il faut faire attention à faire la distinction entre le type à la compilation d'une variable et le type d'exécution réel (trouvé par .GetType() ).

Dans le premier morceau de code, dans la branche où val n'est pas String au moment de l'exécution, nous déclarons:

var v = new JsonString {Value = val};

Ici, var est substitué par JsonString puisqu'il s'agit du type à la compilation du côté droit de l'affectation = . Ensuite, l'instance de type anonyme:

new { keyName, v }

va être une classe (je l'appellerai class Anonymous1 ) avec un membre

public JsonString v { get { ... } }

Maintenant, dans le deuxième morceau de code, nous avons plutôt:

var v = val.GetType() != typeof (String)
        ? new JsonString {Value = val}
        : val;

Les types de compilation des opérandes pour l'opérateur ternaire sont les suivants:

{bool} ? {JsonString} : {object}

Au moment de la compilation, un meilleur type commun pour JsonString et object doit être trouvé. Ce type commun est un object . Donc, object devient le type de compilation de v ici, c.-à-d. var signifie object ici.

Alors le type anonyme:

new { keyName, v }

est un type " Anonumous2 " dont la propriété "2nd" se lit comme suit:

public object v { get { ... } }

Donc , pour résumer: Dans le premier cas , vous passez dans un objet qui a une propriété v déclarée comme JsonString qui , lorsqu'il est récupéré retourne une JsonSting qui arrive à avoir la gestion du temps JsonString . Dans le deuxième exemple de code, vous transmettez un objet qui possède une propriété v déclarée en tant object qui, une fois extraite, renvoie un object dont le type d' JsonString .

Je ne sais pas trop comment Dapper fonctionne! Mais vraisemblablement, quand il voit (par réflexion?) Que le type de propriété est un object , il appelle simplement .ToString() . Si cet object se trouve être une string type à l'exécution, cela devrait être correct, car string.ToString() est remplacé. Mais JsonString.ToString() n'est pas comme ça.

Lorsque Dapper voit que la propriété est déclarée comme JsonString , Dapper fait quelque chose de plus intelligent que d'appeler .ToString() .


Réponse populaire

En supposant qu'il n'y ait pas de conversion implicite disponible entre JsonString et String, le code du deuxième exemple ne fonctionnera pas. Si une conversion implicite est disponible, vous devez fournir plus d'informations sur l'exception en cours.

Aucune conversion disponible entre JsonString, une variable déclarée avec le type var a un type qui est inféré par le compilateur (( https://msdn.microsoft.com/en-us/library/bb384061.aspx ). Dans ce cas, variable v est de type JsonString ou String en fonction de la partie de l'affectation à laquelle il appartient.Si le compilateur suppose qu'il est de type JsonString, toute affectation avec une chaîne échouera.

Dans votre deuxième exemple de code, la première ligne de code est erronée, car l'assignation entraîne l'affectation de deux types de données différents à la variable v.



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