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 GetType()no ser virtual realmente garantizaba 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 hace mentira acerca de su tipo, sin que sea inmediatamente obvio? Puede que esté profundamente equivocado aquí y me encantaría una aclaración 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
{
}
Entonces, 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, badFoogenera un error Type.
Ahora bien, no sé si esto tiene implicaciones serias basándome en que Eric describió este comportamiento como una " característica increíblemente peligrosa ", pero ¿podría este patrón representar una amenaza creíble?

IFoo.GetTypeyobject.GetTypeno es lo mismo, así que aquí no pasa nada malo excepto el estilo pobre. Editar: generalmenteGetTypese llamará a algún objeto desconocido en tiempo de compilación, en la mayoría de los casosobjecty no a una interfaz poco fiable. :)GetType, con la misma firma. Eso no se relaciona con elGetTypemétodo que es importante. También puede crear un método de instancia pública que oculte elGetTypemétodo relevante , utilizando lanewpalabra clave modificadora. Tenga en cuenta que si tiene un método genérico comostatic Type Test<T>(T t) { return t.GetType(); }(sin restriccionesT), entonces cosas comoTest<IFoo>(new BadFoo())seguirán llamando alGetTypemétodo original .Respuestas:
¡Buena pregunta! A mi modo de ver, solo se podría engañar a un compañero desarrollador si GetType fuera virtual en el objeto, que no lo es.
Lo que hizo es similar a sombrear GetType, así:
con esta clase (y usando el código de muestra de MSDN para el método GetType () ) podría tener:
entonces, ¡ay, has mentido con éxito, verdad? Bueno, sí y no ... Considere que usar esto como un exploit significaría usar su instancia BadFoo como un argumento para un método en algún lugar, que espera probablemente un
objecttipo base común o uno para una jerarquía de objetos. Algo como esto:pero
CheckIfInt(foo)imprime "no un int".Entonces, básicamente (volviendo a su ejemplo), en realidad solo podría explotar su "tipo mentiroso" con el código que alguien escribió en su
IFoointerfaz, que es muy explícito sobre el hecho de que tiene unGetType()método "personalizado" .Solo si GetType () fuera virtual en el objeto, podría crear un tipo "mentiroso" que podría usarse con métodos como el
CheckIfIntanterior para crear estragos en las bibliotecas escritas por otra persona.fuente
Hay dos formas de estar seguro sobre el tipo:
Usar
typeofen el tipo que no se puede sobrecargarTransmita la instancia a un
objecty llame alGetType()métodofuente
typeofen un método que solo obtiene unIFoo badFooparámetro como?typeofno se puede aplicar a instancias de una clase, que es lo que debemos hacer aquí. Tu única opción esGetType().BadFoo" pero no "obtienen el tipo de variablebadFoo".No, no puedes hacer que GetType mienta. Solo está introduciendo un nuevo método. Solo el código que conoce este método lo llamará.
Por ejemplo, no puede hacer que un código de marco o de terceros llame a su nuevo método 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 tal declaración. Cualquier código que se compile con su declaración y que use parámetros o variables escritos como IFoo o cualquier tipo derivado de eso usará su nuevo método en su lugar. Pero dado que eso solo afecta a su propio código, realmente no impone una "amenaza".
Si desea proporcionar una descripción de tipo personalizado para una clase esto debe hacerse utilizando un descriptor de tipo personalizado , tal vez mediante la anotación de su clase con un TypeDescriptionProviderAttribute . Esto puede resultar útil en algunas situaciones.
fuente
Bueno, en realidad ya existe un tipo que puede estar en
GetType: cualquier tipo anulable.Este código :
salidas
True.En realidad, no
int?es quién miente, solo el elenco implícito seobjectconvierteint?en una cajaint. Sin embargo, no se puede distinguirint?desde elintprincipioGetType().fuente
GetType()produce un resultado algo extraño. De hecho, le pregunté a varios colegas si un no sombreadoGetType()puede devolver algo que difiera del tipo de tiempo de ejecución del objeto real, la respuesta de todos fue 'no'.No creo que lo haga, ya que cada código de biblioteca que llame a GetType declarará la variable como 'Objeto' o como un tipo genérico 'T'
El siguiente código:
huellas dactilares:
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
fuente
Lo peor que puede suceder hasta donde yo sé es engañar a los programadores inocentes que utilizan la clase envenenada, por ejemplo:
Si
myInstancees una instancia de una clase como la que describe en la pregunta, simplemente se tratará como de tipo desconocido.Entonces mi respuesta es no, no veo ninguna amenaza real aquí.
fuente
Object.GetType()es distinto deSomeUserdefinedInterfaceClassOrStruct.GetType(). Solo que, si usa eldynamictipo, nunca podrá saber qué sucederá en el momento de la vinculación. Entonces deberías usardynamic x = expression; ... Type t = ((object)x).GetType();en casos como ese.Tienes algunas opciones si quieres jugar seguro contra ese tipo de piratería:
Enviar al objeto primero
Puede llamar al
GetType()método original al convertir primero la instancia en unobject:resulta en:
Usar método de plantilla
El uso de este método de plantilla también le dará el tipo real:
fuente
Hay una diferencia entre
object.GetTypeyIFoo.GetType.GetTypese llama en tiempo de compilación en objetos no conocidos, no en interfaces. En su ejemplo, con la salidabadFoo.GetTypese espera un comportamiento, porque sobrecarga el método. Lo único es que otros programadores pueden confundirse con este comportamiento.Pero si lo usa
typeof(), dará como resultado que el tipo es el mismo y no puede sobrescribirtypeof().Además, el programador puede ver en tiempo de compilación qué método
GetTypeinvoca.Entonces, a su pregunta: este patrón no puede representar una amenaza creíble, pero tampoco es el mejor estilo de codificación.
fuente
badFoo.GetType()ES comportamiento esperado, porqueGetTypeestaba sobrecargado.