web-dev-qa-db-fra.com

IsAssignableFrom, IsInstanceOfType et le mot clé is, quelle est la différence?

J'ai une méthode d'extension pour sécuriser les objets de casting, qui ressemble à ceci:

public static T SafeCastAs<T>(this object obj) {
    if (obj == null)
        return default(T);

    // which one I should use?

    // 1. IsAssignableFrom
    if (typeof(T).IsAssignableFrom(obj.GetType()))
        return (T)obj;

    // 2. IsInstanceOfType
    if (typeof(T).IsInstanceOfType(obj))
        return (T) obj;

    // 3. is operator
    if (obj is T)
        return (T) obj;

    return default(T);
}

Comme vous pouvez le voir, j'ai 3 choix, alors lequel devrais-je utiliser? En fait, quelle est la différence entre l'opérateur IsAssignableFrom, IsInstanceOfType et is

33
agent47

Vous utilisez ce que vous avez l'information pour.

Si vous souhaitez vérifier une instance et un type statique, utilisez is.

Si vous n'avez pas le type statique, vous avez juste un objet Type, mais vous voulez vérifier une instance, utilisez IsInstanceOfType.

Si vous ne possédez pas d'instance et que vous souhaitez simplement vérifier la compatibilité entre une instance théorique de Type et une autre Type, utilisez IsAssignableFrom.

Mais en réalité, il semble que vous réimplémentiez simplement l'opérateur as (sauf que le vôtre fonctionnerait également pour les types de valeur non nullables, ce qui n'est généralement pas une grosse limitation).

45
Jacob

J'imagine que vous implémentez effectivement une version de l'opérateur as qui fonctionne avec les types de valeur ainsi que les types de référence.

J'irais pour:

public static T SafeCastAs<T>(this object obj)
{
    return (obj is T) ? (T) obj : default(T);
}

IsAssignableFrom fonctionne avec des types et is fonctionne avec des instances. Ils vous donneront les mêmes résultats dans votre cas, vous devriez donc utiliser la version la plus simple, IMHO.

En ce qui concerne IsInstanceOfType: Ceci est implémenté en termes de IsAssignableFrom, il n'y aura donc aucune différence.

Vous pouvez le prouver en utilisant Reflector pour examiner la définition de IsInstanceOfType():

public virtual bool IsInstanceOfType(object o)
{
    if (o == null)
    {
        return false;
    }
    return this.IsAssignableFrom(o.GetType());
}
10
Matthew Watson

Je suppose que vous devriez juste aller avec " comme " à la place de votre "SafeCastAs" personnalisé. Mais cela ne fonctionnera que pour les classes (pas les structures), donc si vous voulez utiliser cette méthode pour les structures aussi, je peux l’obtenir.

L'opérateur "is" vous donne fondamentalement la même chose que Type.IsAssignableFrom, de sorte que vous ne pouvez conserver que "est", il vérifie si vous pouvez convertir en toute sécurité obj en T, sans exception. Donc, cela couvrira les deux vérifications précédentes de votre méthode. Mais sachez que cela ne vérifie pas si vous pouvez affecter obj à T, à cause des conversions définies par l'utilisateur: explicit et implicite keywords. 

3
outcoldman

Ces fonctions et opérateurs ont une signification différente. Si vous avez des objets, vous pouvez toujours obtenir des types. donc vous ne travaillez pas sur ce que vous avez, mais vous faites ce qui doit être fait.

Lorsque vous travaillez avec une hiérarchie de classes, les différences sont très claires.

Regardez l'exemple suivant

      class ABase
        {

        }

        class BSubclass : ABase
        {

        }
    ABase aBaseObj = new ABase();
                BSubclass bSubclassObj = new BSubclass();

                ABase subObjInBaseRef = new BSubclass();

Différentes opérations donnent des résultats différents.

typeof(ABase).IsInstanceOfType(aBaseObj) = True

typeof(ABase).IsInstanceOfType(bSubclassObj) = True

typeof(ABase).IsInstanceOfType(bSubclassObj) = True

typeof(BSubclass).IsInstanceOfType(aBaseObj) = False

bSubclassObj is ABase = True

aBaseObj is BSubclass = False

subObjInBaseRef is BSubclass = True

subObjInBaseRef is BSubclass = True

typeof(ABase).IsAssignableFrom(typeof(BSubclass))  = True

typeof(BSubclass).IsAssignableFrom(typeof(ABase))= False

Dans le cas où aucune hiérarchie ne serait, tout aurait été pareil . Mais si vous travaillez avec une hiérarchie, IsAssignableFrom, is et IsInstanceOfType donnent des résultats différents.

Il y a plus de combinaisons possibles qui pourraient être essayées. Par exemple, vous pouvez introduire une classe C qui n’est en aucun cas liée aux classes existantes dans cet exemple.

0
Sandeep Dixit