variable tipos long data c# types

c# - tipos - GetType() puede mentir?



variable c# definition (8)

Basado en la siguiente pregunta hecha hace unos días en SO: GetType () y polimorfismo y leyendo la respuesta de Eric Lippert , comencé a pensar si hacer que GetType() no fuera virtual realmente aseguraba que un objeto no pudiera mentir sobre su Type .

Específicamente, la respuesta de Eric dice lo siguiente:

Los diseñadores de frameworks no van a agregar una característica increíblemente peligrosa, como permitir que un objeto mienta sobre su tipo simplemente para que sea consistente con otros tres métodos del mismo tipo.

Ahora la pregunta es: ¿puedo hacer un objeto que mienta sobre su tipo sin que sea inmediatamente obvio? Puedo estar profundamente equivocado aquí y me gustaría aclarar si ese es el caso, pero considere el siguiente código:

public interface IFoo { Type GetType(); }

Y las siguientes dos implementaciones de dicha interfaz:

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

Luego, si ejecuta el siguiente programa simple:

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(); }

Efectivamente, badFoo genera un Type erróneo.

Ahora no sé si esto tiene implicaciones serias basadas en que Eric describa este comportamiento como una " característica increíblemente peligrosa ", pero ¿podría este patrón representar una amenaza creíble?


¡Buena pregunta! De la forma en que lo veo, solo se puede engañar a un compañero desarrollador si GetType tiene un objeto virtual, pero no es así.

Lo que hiciste es similar a sombrear GetType, así:

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

con esta clase (y utilizando el código de ejemplo de MSDN para el método GetType () ), de hecho podría tener:

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

así que, sí, has mentido con éxito, ¿verdad? Bueno, sí y no ... Considere que usar esto como un exploit significaría utilizar su instancia de BadFoo como argumento para un método en alguna parte, que espera probablemente un object o un tipo de base común para una jerarquía de objetos. Algo como esto:

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"); } }

pero CheckIfInt(foo) imprime "not an int".

Entonces, básicamente (volviendo a su ejemplo), realmente solo podría explotar su "tipo mentiroso" con el código que alguien escribió contra su interfaz IFoo , que es muy explícito sobre el hecho de que tiene un método GetType() "personalizado".

Solo si GetType () fuera un objeto virtual, podría crear un tipo "acostado" que podría usarse con métodos como CheckIfInt anterior para crear estragos en bibliotecas escritas por otra persona.


Bueno, en realidad ya hay un tipo que puede estar en GetType : cualquier tipo que GetType .

Este código :

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

salidas True .

En realidad, no es el int? ¿Quién está mintiendo, solo un elenco implícito para hacer object int? en una caja en int . Pero, sin embargo, no se puede decir int? de int con GetType() .


Hay dos formas de estar seguro sobre el Tipo:

  1. Utilice typeof en el tipo que no se puede sobrecargar

    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. Emitir la instancia a un object y llamar al 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();


Hay una diferencia entre object.GetType y IFoo.GetType . GetType se llama en tiempo de compilación en objetos no conocidos, y no en Interfaces. En su ejemplo, con la salida badFoo.GetType se espera un comportamiento, porque sobrecarga el método. Lo único es que otros programadores pueden confundirse con este comportamiento.

Pero si usa typeof() dará como resultado que el tipo es el mismo, y no puede sobrescribir typeof() .

También el programador puede ver en tiempo de compilación, qué método GetType invoca.

Así que a su pregunta: este patrón no puede representar una amenaza creíble, pero tampoco es el mejor estilo de codificación.


Lo peor que puede pasar, por lo que puedo decir es que los programadores inocentes que usan la clase envenenada engañan, por ejemplo:

Type type = myInstance.GetType(); string fullName = type.FullName; string output; if (fullName.Contains(".Web")) { output = "this is webby"; } else if (fullName.Contains(".Customer")) { output = "this is customer related class"; } else { output = "unknown class"; }

Si myInstance es una instancia de una clase como la que describes en la pregunta, solo se tratará como un tipo desconocido.

Entonces mi respuesta es no, no puedo ver ninguna amenaza real aquí.


No creo que sea así, ya que cada código de biblioteca que llama a GetType declarará la variable como ''Objeto'' o como un tipo genérico ''T''

El siguiente código:

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()); }

huellas dactilares:

Objeto BadFoo dice que es un ''TypeConcept.BadFoo''

El objeto NiceFoo dice que es un ''TypeConcept.NiceFoo''

Tipo genérico BadFoo dice que es un ''TypeConcept.BadFoo''

Tipo genérico NiceFoo dice que es un ''TypeConcept.NiceFoo''

La única vez que este tipo de código dará como resultado un mal escenario es en su propio código, donde declara el tipo de parámetro como 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 dice que es un ''System.Int32''

IFoo NiceFoo dice que es un ''TypeConcept.NiceFoo''


No, no puedes hacer que GetType mienta. Usted solo está presentando un nuevo método. Solo el código que tenga conocimiento de este método lo llamará.

No puede, por ejemplo, hacer que un código de terceros llame al nuevo método de GetType en lugar del real, ya que ese código no sabe que su método existe y, por lo tanto, nunca lo llamará.

Sin embargo, puede confundir a sus propios desarrolladores con dicha declaración. Cualquier código que se compila con su declaración y que usa parámetros o variables tipeados como IFoo o cualquier tipo derivado de eso usará su nuevo método. Pero dado que eso solo afecta tu propio código, en realidad no impone una "amenaza".

Si desea proporcionar una descripción de tipo personalizado para una clase, debe hacerlo utilizando un Descriptor de tipo personalizado , tal vez anotando su clase con un TypeDescriptionProviderAttribute . Esto puede ser útil en algunas situaciones.


Tienes algunas opciones si quieres jugar a salvo contra ese tipo de pirateo:

Emitir a objeto primero

Puede llamar al método GetType() original al primer GetType() la instancia a un object :

Console.WriteLine("BadFoo says he''s a ''{0}''", ((object)badFoo).GetType());

resultados en:

BadFoo says he''s a ''ConsoleApplication.BadFoo''

Usar el método de la plantilla

Usar este método de plantilla también le dará el tipo real:

static Type GetType<T>(T obj) { return obj.GetType(); } GetType(badFoo);