Casting vs à l'aide de l' " comme mot-clé dans la CLR
Lors de la programmation d'interfaces, j'ai trouvé que je fais beaucoup de moulage ou de l'objet de la conversion de type.
Est-il une différence entre ces deux méthodes de conversion? Si oui, y a une différence de coût ou comment cela affecte mon programme?
public interface IMyInterface
{
void AMethod();
}
public class MyClass : IMyInterface
{
public void AMethod()
{
//Do work
}
//Other helper methods....
}
public class Implementation
{
IMyInterface _MyObj;
MyClass _myCls1;
MyClass _myCls2;
public Implementation()
{
_MyObj = new MyClass();
//What is the difference here:
_myCls1 = (MyClass)_MyObj;
_myCls2 = (_MyObj as MyClass);
}
}
Aussi, ce qui est "en général" la méthode préférée?
- Pourriez-vous ajouter un petit exemple de la raison pour laquelle vous utilisez le jette en premier lieu à la question, ou peut-être en commencer une nouvelle? Je suis plutôt intéressé par savoir pourquoi vous avez besoin de la fonte de l'unité de test. Je pense que c'est en dehors de la portée de cette question.
- Je peux probablement changer mon test de l'unité pour éviter ce besoin pour cela. En gros, ça revient au fait que j'ai un bien sur mon objet concret qui n'est pas dans l'interface. J'ai besoin de cette propriété, mais la vie réelle que les biens ont été réglés par d'autres moyens. Ne fait que répondre à votre question?
- Comme Patrik Hägne astucieusement les points ci-après, il y a une différence.
Vous devez vous connecter pour publier un commentaire.
La réponse en dessous de la ligne a été écrit en 2008.
C# 7 a introduit la correspondance de modèle, qui a en grande partie remplacé le
as
opérateur, vous pouvez maintenant écrire:Noter que
tt
est toujours dans la portée, mais certainement pas attribué. (Il est certainement affectés au sein de l'if
corps.) C'est un peu ennuyeux, dans certains cas, donc, si vous vous souciez vraiment de présentant le plus petit nombre de variables possibles dans chaque champ, vous pouvez toujours utiliseris
suivie par un casting.Je ne pense pas que les réponses jusqu'à présent (à l'époque, à partir de cette réponse!) ont vraiment expliqué où ça vaut le coup à l'aide de lequel.
Ne pas faire ceci:
Ce n'est pas seulement de vérifier deux fois, mais il est peut-être la vérification de choses différentes, si
randomObject
est un domaine plutôt qu'une variable locale. Il est possible que le "si" à passer, mais ensuite le casting à l'échec, si un autre thread modifie la valeur derandomObject
entre les deux.Si
randomObject
vraiment devrait être une instance deTargetType
, c'est à dire si elle ne l'est pas, cela signifie qu'il ya un bug, le casting, c'est la bonne solution. Qui lève une exception immédiatement, ce qui signifie que le travail est fait sous des hypothèses erronées, et à l'exception affiche correctement le type de bug.Si
randomObject
pourrait être une instance deTargetType
etTargetType
est un type de référence, puis utiliser le code comme ceci:Si
randomObject
pourrait être une instance deTargetType
etTargetType
est un type valeur, alors nous ne pouvons pas utiliseras
avecTargetType
lui-même, mais nous pouvons utiliser un type nullable:(Remarque: actuellement, c'est en fait plus lentement que est de + en fonte. Je pense que c'est plus élégant et cohérent, mais il nous continuons.)
Si vous n'avez pas vraiment besoin de la valeur convertie, mais vous avez juste besoin de savoir si il est une instance de TargetType, puis le
is
opérateur est votre ami. Dans ce cas, il n'a pas d'importance si TargetType est un type de référence ou une valeur de type.Il peut y avoir d'autres cas impliquant des médicaments génériques où
is
est utile (parce que vous ne pouvez pas savoir si T est un type référence ou pas, de sorte que vous ne peut pas utiliser), mais ils sont relativement obscure.J'ai presque certainement utilisé
is
pour le type de la valeur de cas jusqu'à maintenant, n'ayant pas pensé à utiliser un type nullable etas
ensemble 🙂EDIT: Notez qu'aucune de ces pourparlers au sujet de la performance autre que la valeur de type de cas, où j'ai noté que unboxing à nullable type de valeur est en fait plus lente, mais constante.
Comme par naasking réponse, est-et de la fonte ou est-et-les aussi vite que comme-et-null-vérifier moderne, avec des équipes communes d'enquête, comme le montre le code ci-dessous:
Sur mon ordinateur portable, ces toutes exécuter dans à propos de 60ms. Deux choses à noter:
Afin de ne pas laisser s'inquiéter de la performance. Nous allons vous soucier de l'exactitude et de la cohérence.
Que je maintiens, c'est-à-et-cast (ou est-et-as) sont à la fois dangereux lorsqu'ils traitent avec des variables, comme le type de la valeur qu'il désigne peut changer en raison d'un autre thread entre le test et la fonte. Qui serait assez rare de la situation - mais je préfère avoir une convention qui je peux utiliser de manière cohérente.
J'ai aussi maintenir que l'as-puis-null-vérifier donne une meilleure séparation des préoccupations. Nous avons une déclaration qui tente une conversion, puis une instruction qui utilise le résultat. L'est-et de la fonte ou est-et comme on l'effectue un test et puis une autre tentative pour convertir la valeur.
Pour le dire d'une autre façon, quelqu'un aurait-il jamais écrire:
C'est en quelque sorte de ce qui est-et-cast est en train de faire - bien que, évidemment, dans un lieu beaucoup moins cher.
is
suivie par cast) n'est pas mauvais, la façon de s'écraser, c'est mauvais. Ce n'est pas un comportement incorrect, c'est juste plus IL. Si c'est nettement plus lent pour un utilisateur dépend de nombreux facteurs, y compris l'équipe de traitement d'un IL, combien de fois ce code s'exécute, et où/comment/quand il s'exécute. Je fais toujours de mieux en codant pour plus de clarté, & de la justesse d'abord, et de l'optimisation de la performance plus tard.is
/cast
est 2x plus onéreuse queas
".if (randomObject is TargetType convertedRandomObject){ // Do stuff with convertedRandomObject.Value}
ou de l'utilisationswitch
/case
voir les docs"comme" renvoie la valeur NULL si pas possible de le lancer.
casting avant va lever une exception.
De la performance, de lever une exception est généralement plus coûteuse en temps.
Voici une autre réponse, avec quelques IL de comparaison. Considérons la classe:
Maintenant, regardez le IL chaque méthode produit. Même si l'op codes ne signifient rien pour vous, vous pouvez voir une différence majeure: isinst est appelée, suivi par castclass dans le DirectCast méthode. Donc, de deux appels au lieu d'un gros.
La isinst mot-clé par rapport à la castclass
Ce blog a une bonne comparaison entre les deux façons de le faire. Son résumé est:
Personnellement, j'ai toujours l'utiliser Comme, parce que c'est facile à lire et est recommandé par le .NET de l'équipe de développement ou de Jeffrey Richter, de toute façon)
L'un des plus subtiles différences entre les deux est que le "comme" mot-clé ne peut pas être utilisé pour la coulée lorsqu'un opérateur de cast est en cause:
Ce ne compile pas (même si je pense que dans les versions précédentes) sur la dernière ligne depuis le "comme" mots-clés de ne pas prendre des opérateurs de transtypage en compte. La ligne
string cast = (string)f;
fonctionne parfaitement bien.comme jamais déclenche une exception si elle ne peut pas effectuer la conversion de retour null à la place (comme fonctionne sur les types de référence uniquement). Donc, en utilisant comme est essentiellement équivalent à
C-style de moulages, d'autre part, de lancer une exception si aucune conversion n'est possible.
Pas vraiment une réponse à votre question, mais ce que je pense est un point important.
Si vous êtes à la programmation d'une interface vous ne devriez pas avoir besoin de cast. Espérons que ces distributions sont très rares. Si non vous avez probablement besoin de revoir certains de vos interfaces.
S'il vous plaît ignorer Jon Skeet conseils, re:éviter les tester et en fonte motif, c'est à dire.:
À l'idée que cela coûte plus cher qu'un casting et une valeur null est un test MYTHE:
C'est un micro-optimisation qui ne fonctionne pas. J'ai couru certains des tests réels, et de tester-et-cast est effectivement plus rapide que la distribution-et-null-comparaison, et c'est aussi plus sûr parce que vous n'avez pas la possibilité d'avoir une référence null dans le champ d'application à l'extérieur de la si faut le casting échouer.
Si vous voulez une bonne raison de tester-et-cast est plus rapide, ou au moins pas plus lent, il y a un simple et complexe à la raison.
Simple: même naïf compilateurs fusionner deux opérations similaires, comme test-et-cast, dans un seul test et de la direction générale. distribution-et-null-test peut forcer deux essais et une branche, un pour le type de test et de la conversion à null en cas d'échec, l'un pour les nuls vérifier lui-même. À tout le moins, ils seront à la fois de les optimiser en un seul test et de la branche, afin de tester et de fonte n'est ni lent ni rapide que cast-et-null-test.
Complexe: pourquoi tester et de fonte est plus rapide: cast-et-null-test introduit une autre variable à l'extérieur de la portée, le compilateur doit suivre pour liveness, et il peut ne pas être en mesure d'optimiser loin que variable selon la complexité de votre flux de contrôle est. À l'inverse, test-et-cast introduit une nouvelle variable que dans délimité dans le champ d'application de sorte que le compilateur sait que la variable est mort après que le champ d'application des sorties, et peut donc optimiser l'allocation des registres de mieux.
De sorte s'il vous plaît, s'il vous PLAÎT laissez ce "cast-et-null-est le meilleur test que test-et-cast" les conseils de MOURIR. S'il vous PLAÎT. test-et-cast est à la fois plus sûr et plus rapide.
ref
paramètre. Il est sans danger pour les variables locales, mais pas pour les champs. Je serais intéressé pour exécuter vos critères de référence, mais le code que vous avez donné dans votre blog n'est pas complète. Je suis d'accord avec pas de micro-optimisation, mais je ne pense pas que l'aide de la valeur est deux fois plus lisible et élégante que l'aide de "comme" et un test de nullité. (Je serais certainement utiliser une droite en fonte plutôt que "que" après une, btw.)Si la conversion échoue, le "comme" mot-clé ne lance pas d'exception; il définit la variable à null (ou à sa valeur par défaut pour les types de valeur) à la place.
Ce n'est pas une réponse à la question mais les commentaires à la question de l'exemple de code:
Habituellement, vous ne devriez pas avoir à jeter un Objet, par exemple, le IMyInterface MyClass. La grande chose au sujet des interfaces est que si vous prenez un objet en entrée qui implémente une interface, que vous n'avez pas de soins de quel type d'objet que vous obtenez.
Si vous lancez IMyInterface MyClass, que vous avez déjà supposer que vous obtenez un objet de type Maclasse et il ne fait aucun sens d'utiliser IMyInterface, parce que si vous nourrissez votre code avec d'autres classes qui implémentent IMyInterface, il serait briser votre code...
Maintenant, mon conseil: si vos interfaces sont bien conçus, vous pouvez éviter beaucoup de typecasting.
La
as
opérateur peut être utilisé uniquement sur les types de référence, il ne peut pas être surchargé, et il sera de retournull
si l'opération échoue. Il ne sera jamais lever une exception.De la coulée peut être utilisé sur tous les types compatibles, il peut être surchargé, et il va lever une exception si l'opération échoue.
Dont le choix dépend des circonstances. Principalement, c'est une question de savoir si vous souhaitez lancer une exception sur un échec de conversion.
Ma réponse est seulement une question de vitesse dans les cas où nous n'avons pas vérifier le type et nous n'avons pas de vérifier les valeurs null après la coulée. J'ai ajouté deux autres tests de Jon Skeet code:
Résultat:
Ne pas essayer de se concentrer sur la vitesse (comme je l'ai fait), parce que c'est très très rapide.
as
de conversion (sans la vérification des erreurs) était d'environ 1 à 3% plus rapide que le casting (autour de 540ms rapport à 550ms sur 100 millions d'itérations). Ni va faire ou défaire votre application.En plus de tout ce qui a été déjà exposé ici, je viens de tomber sur une différence pratique je pense est intéressant de noter, entre une conversion explicite
rapport à l'aide de la
as
opérateur.Voici l'exemple:
Ligne du bas: GenericCaster2 ne fonctionnera pas avec struct types. GenericCaster volonté.
Si vous utilisez le Bureau Pia ciblage de l' .NET Framework 4.X, vous devez utiliser le comme de mots clés, sinon il ne sera pas compilé.
Casting est OK, alors que le ciblage .NET 2.0 si:
Lors du ciblage .NET 4.X les erreurs sont:
erreur CS0656: Manquant compilateur nécessaire membre " de Microsoft.CSharp.RuntimeBinder.Classeur.Convertir'
erreur CS0656: Manquant compilateur nécessaire membre " de Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Créer des"
La
as
mot clé fonctionne de la même comme un cast explicite entre compatible avec les types de référence à la grande différence qu'il ne génère pas d'exception si la conversion échoue. Plutôt, elle donne une valeur null dans la variable cible. Depuis les Exceptions sont très coûteux en termes de performances, il est considéré comme une bien meilleure méthode de coulée.Ce que vous choisissez dépend fortement de ce qui est demandé.
Je préfère une conversion explicite
parce que si l'objet doit par de IMyInterface type et il n'est pas - il est certainement un problème.
Il est préférable d'obtenir d'erreur dès que possible, parce que l'erreur exacte sera fixée à la place de la fixation de ses effets secondaires.
Mais si vous traitez avec des méthodes qui accepte
object
en paramètre, alors vous devez vérifier son type exact avant d'exécuter tout code. Dans de tels casas
serait utile de sorte que vous pouvez éviterInvalidCastException
.Il dépend, voulez-vous de vérifier la valeur null après l'utilisation de "comme" ou préférez-vous que votre application pour lancer une exception?
Ma règle d'or est que si je m'attends toujours à ce que la variable est du type, je m'attends à le temps que je veux-je utiliser un cast. Si il est possible que la variable ne sera pas exprimés à ce que je veux et je suis prêt à gérer les valeurs null de sous, je vais utiliser comme.
Jetez un oeil à ces liens:
ils vous montrer quelques détails et de tests de performance.
L'OP problème est limité à un casting situation. Le titre couvre beaucoup plus de situations.
Voici un aperçu de tous les casting des situations que je peux penser: