Question

Considérez le code suivant:

void Handler(object o, EventArgs e)
{
   // I swear o is a string
   string s = (string)o; // 1
   //-OR-
   string s = o as string; // 2
   // -OR-
   string s = o.ToString(); // 3
}

Quelle est la différence entre les trois types de casting (d'accord, le troisième n'est pas un casting, mais vous obtenez le but). Lequel devrait être préféré?

Était-ce utile?

La solution

string s = (string)o; // 1

Lance InvalidCastException si o est pas une chaîne . Sinon, affecte o à s , même si o est null .

string s = o as string; // 2

Assigne null à s si o n'est pas une chaîne ou si o est null . Pour cette raison, vous ne pouvez pas l'utiliser avec des types de valeur (l'opérateur ne pourrait jamais renvoyer null dans ce cas). Sinon, attribue o à s .

string s = o.ToString(); // 3

Provoque une NullReferenceException si o est null . Attribue tout o.ToString () qui retourne à s , quel que soit le type o .

Utilisez 1 pour la plupart des conversions - c’est simple et direct. J'ai tendance à ne presque jamais utiliser 2, car si quelque chose ne convient pas, je m'attends généralement à ce qu'une exception se produise. J'ai seulement constaté un besoin de ce type de fonctionnalité return-null avec des bibliothèques mal conçues qui utilisent des codes d'erreur (par exemple, return null = error, au lieu d'utiliser des exceptions).

3 n'est pas un cast et est simplement une invocation de méthode. Utilisez-le lorsque vous avez besoin de la représentation sous forme de chaîne d'un objet non-chaîne.

Autres conseils

  1. chaîne s = (chaîne) o; À utiliser quand quelque chose devrait certainement être l'autre chose.
  2. chaîne s = o comme chaîne; À utiliser lorsque quelque chose peut être l'autre chose.
  3. chaîne s = o.ToString (); À utiliser quand vous ne vous en souciez pas mais vous voulez juste utiliser le représentation de chaîne disponible.

Cela dépend vraiment de savoir si vous savez si o est une chaîne et ce que vous voulez en faire. Si votre commentaire signifie que o est vraiment une chaîne, je préférerais le transtypage (chaîne) o - il est peu probable qu'il échoue.

Le plus grand avantage de l'utilisation de la diffusion directe est que, en cas d'échec, vous obtenez un InvalidCastException , qui vous indique en gros ce qui ne va pas.

Avec l'opérateur en tant que , si o n'est pas une chaîne, s est défini sur null , ce qui est pratique si vous n’êtes pas sûr et que vous voulez tester s :

string s = o as string;
if ( s == null )
{
    // well that's not good!
    gotoPlanB();
}

Toutefois, si vous n'effectuez pas ce test, vous utiliserez s plus tard et aurez un NullReferenceException levée. Celles-ci ont tendance à être plus courantes et pas beaucoup plus difficiles à dépister une fois qu'elles se produisent dans la nature, car presque chaque ligne déréférence une variable et peut en générer une. Par contre, si vous essayez de transtyper vers un type de valeur (toute primitive ou structure telle que DateTime ), vous devez utiliser la distribution simple. Le comme ne fonctionnera pas.

Dans le cas particulier de la conversion en chaîne, chaque objet a un ToString , votre troisième méthode peut donc fonctionner si o n'est pas nul et si vous pensez que La méthode ToString peut faire ce que vous voulez.

Si vous connaissez déjà le type de conversion, utilisez un transtypage de style C:

var o = (string) iKnowThisIsAString; 

Notez que vous ne pouvez effectuer une coercition de type explicite qu'avec un casting de style C.

Si vous ne savez pas s'il s'agit du type souhaité et si vous l'utiliserez, utilisez comme mot clé :

var s = o as string;
if (s != null) return s.Replace("_","-");

//or for early return:
if (s==null) return;

Notez que en tant que n'appellera aucun opérateur de conversion de type. Il ne sera non nul que si l'objet n'est pas null et qu'il est natif du type spécifié.

Utilisez ToString () pour obtenir une représentation sous forme de chaîne lisible par l'homme de tout objet, même s'il ne peut pas être converti en chaîne.

Le mot clé as est correct dans asp.net lorsque vous utilisez la méthode FindControl.

Hyperlink link = this.FindControl("linkid") as Hyperlink;
if (link != null)
{
     ...
}

Cela signifie que vous pouvez utiliser la variable typée plutôt que de devoir la convertir à partir de objet comme vous le feriez avec une diffusion directe:

object linkObj = this.FindControl("linkid");
if (link != null)
{
     Hyperlink link = (Hyperlink)linkObj;
}

Ce n'est pas énorme, mais cela économise des lignes de code et des affectations de variables, en plus il est plus lisible

'as' est basé sur 'is', mot clé qui vérifie au moment de l'exécution si l'objet est compatible polimorphisme (essentiellement si une conversion peut être faite) et renvoie la valeur null si la vérification échoue.

Ces deux sont équivalents:

Utilisation de 'comme':

string s = o as string;

Utiliser 'est':

if(o is string) 
    s = o;
else
    s = null;

Au contraire, la conversion de style c est également effectuée au moment de l'exécution, mais une exception est levée si la conversion ne peut pas être effectuée.

Juste pour ajouter un fait important:

Le mot clé "en tant que" ne fonctionne qu'avec les types de référence. Vous ne pouvez pas faire:

// I swear i is an int
int number = i as int;

Dans ces cas, vous devez utiliser le casting.

2 est utile pour la conversion dans un type dérivé.

Supposons que un soit un animal:

b = a as Badger;
c = a as Cow;

if (b != null)
   b.EatSnails();
else if (c != null)
   c.EatGrass();

recevra un alimenté avec un minimum d'incantations.

Selon les expériences menées sur cette page: http: / /www.dotnetguru2.org/sebastienros/index.php/2006/02/24/cast_vs_as

(cette page contient des erreurs "parfois illégales", alors actualisez si c'est le cas)

La conclusion est que "& as; "" l'opérateur est normalement plus rapide qu'une distribution. Parfois beaucoup plus rapidement, parfois à peine plus vite.

je peronsonone chose " comme " est également plus lisible.

Donc, puisqu'il est à la fois plus rapide et "plus sûr", (ne jettera pas exception), et peut-être plus facile à lire, je recommande d'utiliser " comme "" tout le temps.

& string; o " entraînera une exception InvalidCastException car il n'y a pas de diffusion directe.

& o; chaîne en tant que " s entraînera comme s une référence nulle plutôt qu’une exception.

"o.ToString ()" ce n'est pas une distribution en soi, c'est une méthode implémentée par objet, et donc d'une manière ou d'une autre, par toutes les classes du .net qui "fait quelque chose" avec l'instance de la classe à laquelle il est appelé et renvoie une chaîne.

N'oubliez pas que pour la conversion en chaîne, il existe également Convert.ToString (someType instanceOfThatType) où someType est l'un des types de types, essentiellement les types de base des frameworks.

Toutes les réponses données sont bonnes, si je peux ajouter quelque chose: Pour utiliser directement les méthodes et les propriétés de string (par exemple, ToLower), vous ne pouvez pas écrire:

(string)o.ToLower(); // won't compile

vous pouvez seulement écrire:

((string)o).ToLower();

mais vous pouvez écrire à la place:

(o as string).ToLower();

L'option en tant que est plus lisible (du moins à mon avis).

string s = o as string; // 2

Est préférable, car cela évite la pénalité de double casting en termes de performances.

Il semble que les deux d'entre eux soient conceptuellement différents.

Diffusion directe

Les types ne doivent pas être strictement liés. Il vient dans tous les types de saveurs.

  • Diffusion implicite / explicite personnalisée: généralement, un nouvel objet est créé.
  • Type de valeur implicite: Copier sans perdre d'informations.
  • Valeur explicite: la copie et les informations risquent d'être perdues.
  • Relation IS-A: Modifier le type de référence, sinon génère une exception.
  • Même type: "Le casting est redondant".

On a l'impression que l'objet va être transformé en autre chose.

Opérateur AS

Les types ont une relation directe. Comme dans:

  • Types de référence: Relation IS-A , les objets sont toujours identiques, seule la référence change.
  • Types de valeur: Copier les types boxing et nullable.

Vous avez l’impression que vous allez manipuler l’objet d’une manière différente.

Échantillons et IL

    class TypeA
    {
        public int value;
    }

    class TypeB
    {
        public int number;

        public static explicit operator TypeB(TypeA v)
        {
            return new TypeB() { number = v.value };
        }
    }

    class TypeC : TypeB { }
    interface IFoo { }
    class TypeD : TypeA, IFoo { }

    void Run()
    {
        TypeA customTypeA = new TypeD() { value = 10 };
        long longValue = long.MaxValue;
        int intValue = int.MaxValue;

        // Casting 
        TypeB typeB = (TypeB)customTypeA; // custom explicit casting -- IL:  call class ConsoleApp1.Program/TypeB ConsoleApp1.Program/TypeB::op_Explicit(class ConsoleApp1.Program/TypeA)
        IFoo foo = (IFoo)customTypeA; // is-a reference -- IL: castclass  ConsoleApp1.Program/IFoo

        int loseValue = (int)longValue; // explicit -- IL: conv.i4
        long dontLose = intValue; // implict -- IL: conv.i8

        // AS 
        int? wraps = intValue as int?; // nullable wrapper -- IL:  call instance void valuetype [System.Runtime]System.Nullable`1<int32>::.ctor(!0)
        object o1 = intValue as object; // box -- IL: box [System.Runtime]System.Int32
        TypeD d1 = customTypeA as TypeD; // reference conversion -- IL: isinst ConsoleApp1.Program/TypeD
        IFoo f1 = customTypeA as IFoo; // reference conversion -- IL: isinst ConsoleApp1.Program/IFoo

        //TypeC d = customTypeA as TypeC; // wouldn't compile
    }

J'aimerais attirer l'attention sur les spécificités suivantes de l'opérateur en tant que :

https://docs.microsoft.com / fr-fr / dotnet / csharp / langue-reference / keywords / as

  

Notez que l'opérateur as n'effectue que des conversions de référence,   conversions nullables et conversions de boxe. L'opérateur en tant que ne peut pas   effectuer d'autres conversions, telles que des conversions définies par l'utilisateur, qui   devrait plutôt être effectuée à l'aide d'expressions cast.

Lorsque j'essaie d'obtenir la représentation sous forme de chaîne de tout élément (de tout type) pouvant potentiellement être null, je préfère la ligne de code ci-dessous. Il est compact, il appelle ToString () et gère correctement les valeurs NULL. Si o est null, s contiendra String.Empty.

String s = String.Concat(o);

Puisque personne n'en a parlé, l'instance la plus proche de instanceOf to Java est la suivante:

obj.GetType().IsInstanceOfType(otherObj)

Utilisez la chaîne de diffusion directe s = (chaîne) o; si, dans le contexte logique de votre application, chaîne est le seul type valide. Avec cette approche, vous obtiendrez InvalidCastException et implémenterez le principe de Fail- rapide . Votre logique sera protégée contre le dépassement du type non valide ou contre l’exception NullReferenceException si elle est utilisée par en tant que .

Si la logique attend plusieurs types différents, convertissez la chaîne s = o sous la forme d'une chaîne; et vérifiez-le sur null ou utilisez est opérateur.

Une nouvelle fonctionnalité intéressante est apparue dans C # 7.0 pour simplifier la distribution et la vérification est Correspondance de modèle :

if(o is string s)
{
  // Use string variable s
}

or

switch (o)
{
  case int i:
     // Use int variable i
     break;
  case string s:
     // Use string variable s
     break;
 }

Les deux formes suivantes de conversion de type (diffusion) sont prises en charge en C #:

|

(C) v

& # 8226; Convertir le type statique de v en c dans l'expression donnée

& # 8226; Possible uniquement si le type dynamique de v est c ou un sous-type de c

& # 8226; Sinon, une exception InvalidCastException est levée

|

v en tant que C

& # 8226; Variante non fatale de (c) v

& # 8226; Ainsi, convertissez le type statique de v en c dans l'expression donnée

& # 8226; Renvoie la valeur null si le type dynamique de v n'est pas c ou un sous-type de c

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