94 votes

GetType() peut mentir ?

Basé sur la question suivante posée il y a quelques jours, dans: GetType() et le polymorphisme et de la lecture Eric Lippert la réponse, j'ai commencé à penser si GetType() de ne pas être virtuel vraiment fait en sorte qu'un objet ne peut pas mentir à propos de son Type.

Plus précisément, Eric réponse est la suivante:

Le cadre concepteurs ne vont pas à ajouter un incroyablement dangereux comme permettant un objet à mentir à propos de son type, simplement pour le rendre compatible avec les trois autres méthodes du même type.

Maintenant, la question est: puis-je faire un objet qui ne se mentir à propos de son type, sans qu'il soit immédiatement évident? J'ai peut-être profondément mal ici, et j'aimerais des précisions si c'est le cas, mais considérons le code suivant:

public interface IFoo
{
    Type GetType();
}

Et dans les deux implémentations de ladite interface:

public class BadFoo : IFoo
{
    Type IFoo.GetType()
    {
        return typeof(int);
    }
}

public class NiceFoo : IFoo
{
}

Alors si vous exécutez le programme simple suivant:

static void Main(string[] args)
{
    IFoo badFoo = new BadFoo();
    IFoo niceFoo = new NiceFoo();
    Console.WriteLine("BadFoo says he's a '{0}'", badFoo.GetType().ToString());
    Console.WriteLine("NiceFoo says he's a '{0}'", niceFoo.GetType().ToString());
    Console.ReadLine();
}

Assurez-vous de suffisamment d' badFoo sorties erronée Type.

Maintenant, je ne sais pas si cela a une incidence sérieuse basée sur Eric décrivant ce comportement comme "incroyablement dangereux fonctionnalité", mais ce modèle pourrait poser une menace crédible?

45voto

Paolo Falabella Points 10514

Belle question! La façon dont je le vois, vous ne pouviez vraiment d'induire en erreur un autre développeur si GetType virtuel sur l'objet, il ne l'est pas.

Ce que vous avez fait est semblable à l'occultation GetType, comme ceci:

public class BadFoo
{
    public new Type GetType()
    {
        return typeof(int);
    }
}

avec cette classe (et à l'aide de l'exemple de code à partir de la MSDN pour l'GetType() ) en effet, vous pourriez avoir:

int n1 = 12;
BadFoo foo = new BadFoo();

Console.WriteLine("n1 and n2 are the same type: {0}",
                  Object.ReferenceEquals(n1.GetType(), foo.GetType())); 
// output: 
// n1 and n2 are the same type: True

donc, aïe, vous avez menti, non? Eh bien, oui et non... Estiment que l'utilisation de ce comme un "exploit" signifierait à l'aide de votre BadFoo exemple comme argument à une méthode quelque part, qui attend probablement un object ou l'utilisation d'un type de base pour une hiérarchie d'objets. Quelque chose comme ceci:

public void CheckIfInt(object ob)
{
    if(ob.GetType() == typeof(int))
    {
        Console.WriteLine("got an int! Initiate destruction of Universe!");
    }
    else
    {
        Console.WriteLine("not an int");
    }
}

mais CheckIfInt(foo) imprime pas un "int".

Donc, en gros, (votre exemple), vous pouvez seulement utiliser votre "mensonge type" avec le code que quelqu'un écrit à l'encontre de votre IFoo interface, ce qui est très explicite sur le fait qu'il a une "coutume" GetType() méthode.

Seulement si GetType() a été virtuel sur l'objet que vous serait en mesure de concevoir un "mensonge" type qui peut être utilisé avec des méthodes comme CheckIfInt ci-dessus pour créer des ravages dans les bibliothèques écrites par quelqu'un d'autre.

32voto

Johannes Wanzek Points 1713

Il y a deux façons d'être sûr du type:

  1. Utilisez typeof sur le type qui ne peut pas être surchargé

     IFoo badFoo = new BadFoo();
    IFoo niceFoo = new NiceFoo();
    
    Console.WriteLine("BadFoo says he's a '{0}'", badFoo.GetType().ToString());
    Console.WriteLine("NiceFoo says he's a '{0}'", niceFoo.GetType().ToString());
    
    Console.WriteLine("BadFoo really is a '{0}'", typeof(BadFoo));
    Console.WriteLine("NiceFoo really is a '{0}'", typeof(NiceFoo));
    Console.ReadLine();
     
  2. Transforme l'instance en object et appelle la méthode GetType()

     IFoo badFoo = new BadFoo();
    IFoo niceFoo = new NiceFoo();
    
    Console.WriteLine("BadFoo says he's a '{0}'", badFoo.GetType().ToString());
    Console.WriteLine("NiceFoo says he's a '{0}'", niceFoo.GetType().ToString());
    
    Console.WriteLine("BadFoo really is a '{0}'", ((object)badFoo).GetType());
    Console.WriteLine("NiceFoo really is a '{0}'", ((object)niceFoo).GetType());
    Console.ReadLine();
     

10voto

Mårten Wikström Points 3412

Non, vous ne pouvez pas faire GetType mensonge. Vous êtes seulement l'introduction d'une nouvelle méthode. Seul code qui sont au courant de cette méthode appelle.

Vous ne pouvez pas par exemple faire un tiers ou à un cadre d'appeler du code de votre nouvelle méthode GetType au lieu de le vrai, depuis que le code ne savez pas que votre méthode existe et ne sera donc jamais l'appeler.

Vous pouvez toutefois de confondre votre propre développeurs avec une telle déclaration. Tout le code est compilé avec votre déclaration et que l'utilisation de paramètres ou de variables typées comme IFoo ou tout autre type dérivé de ce sera en effet l'utilisation de votre nouvelle méthode à la place. Mais depuis que seulement affecte votre propre code, il n'a pas vraiment d'imposer une "menace".

Si vous ne souhaitez fournir un type personnalisé description d'une classe, cela devrait être fait à l'aide d'un Personnalisé du Descripteur de Type, peut-être par l'annotation de votre classe avec un TypeDescriptionProviderAttribute. Cela peut être utile dans certaines situations.

7voto

Vlad Points 23480

Eh bien, en fait, il est déjà un type qui peut se situer en GetType: tout type nullable.

Ce code:

int? x = 0; int y = 0;
Console.WriteLine(x.GetType() == y.GetType());

sorties True.


En fait, ce n'est pas l' int? qui est le mensonge, juste implicite jeté à l' object virages int? dans un coffret int. Mais néanmoins, vous ne peut pas dire int? de int avec GetType().

5voto

Moeri Points 2310

Je ne pense pas que ça, car à chaque bibliothèque de code qui appelle GetType pour déclarer la variable comme Objet ou comme un type Générique de 'T'

Le code suivant:

    public static void Main(string[] args)
    {
        IFoo badFoo = new BadFoo();
        IFoo niceFoo = new NiceFoo();
        PrintObjectType("BadFoo", badFoo);
        PrintObjectType("NiceFoo", niceFoo);
        PrintGenericType("BadFoo", badFoo);
        PrintGenericType("NiceFoo", niceFoo);
    }

    public static void PrintObjectType(string actualName, object instance)
    {
        Console.WriteLine("Object {0} says he's a '{1}'", actualName, instance.GetType());
    }

    public static void PrintGenericType<T>(string actualName, T instance)
    {
        Console.WriteLine("Generic Type {0} says he's a '{1}'", actualName, instance.GetType());
    }

impressions:

Objet BadFoo dit qu'il est un " TypeConcept.BadFoo'

Objet NiceFoo dit qu'il est un " TypeConcept.NiceFoo'

Type générique BadFoo dit qu'il est un " TypeConcept.BadFoo'

Type générique NiceFoo dit qu'il est un " TypeConcept.NiceFoo'

La seule fois où ce genre de code, de mauvaises scénario est dans votre propre code, où vous déclarez le type de paramètre que IFoo

    public static void Main(string[] args)
    {
        IFoo badFoo = new BadFoo();
        IFoo niceFoo = new NiceFoo();
        PrintIFoo("BadFoo", badFoo);
        PrintIFoo("NiceFoo", niceFoo);
    }

    public static void PrintIFoo(string actualName, IFoo instance)
    {
        Console.WriteLine("IFoo {0} says he's a '{1}'", actualName, instance.GetType());
    }

IFoo BadFoo dit qu'il est un 'Système.Int32'

IFoo NiceFoo dit qu'il est un " TypeConcept.NiceFoo'

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X