Com base na seguinte pergunta feita há poucos dias no SO: GetType () e polimorfismo e lendo a resposta de Eric Lippert , comecei a pensar se fazer GetType()
não ser virtual realmente garante que um objeto não possa mentir sobre ele Type
.
Especificamente, a resposta de Eric afirma o seguinte:
Os designers do framework não irão adicionar um recurso incrivelmente perigoso, como permitir que um objeto minta sobre seu tipo apenas para torná-lo consistente com três outros métodos do mesmo tipo.
Agora a pergunta é: Eu posso fazer um objeto que faz mentira sobre seu tipo, sem que seja imediatamente óbvio? Posso estar profundamente errado aqui e adoraria um esclarecimento se for esse o caso, mas considere o seguinte código:
public interface IFoo
{
Type GetType();
}
E as seguintes duas implementações da referida interface:
public class BadFoo : IFoo
{
Type IFoo.GetType()
{
return typeof(int);
}
}
public class NiceFoo : IFoo
{
}
Então, se você executar o seguinte programa simples:
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();
}
Com certeza badFoo
produz um erro Type
.
Agora, eu não sei se isso tem alguma implicação séria com base na descrição de Eric desse comportamento como um " recurso incrivelmente perigoso ", mas esse padrão poderia representar uma ameaça confiável?
IFoo.GetType
eobject.GetType
não é a mesma coisa, então nada de ruim está acontecendo aqui, exceto um estilo ruim. Editar: GeralmenteGetType
será chamado em algum objeto desconhecido em tempo de compilação, na maioria dos casos,object
e não em alguma interface duvidosa. :)GetType
, com a mesma assinatura. Isso não se relaciona com oGetType
método que é importante. Você também pode criar um método de instância público que oculte oGetType
método relevante , usando anew
palavra-chave modificadora. Observe, se você tiver um método genérico comostatic Type Test<T>(T t) { return t.GetType(); }
(sem restriçãoT
), então coisas comoTest<IFoo>(new BadFoo())
ainda chamarão oGetType
método original .Respostas:
Boa pergunta! A meu ver, você só poderia realmente enganar um colega desenvolvedor se GetType fosse virtual no objeto, o que não é.
O que você fez é semelhante a sombreado GetType, assim:
com esta classe (e usando o código de amostra do MSDN para o método GetType () ) você realmente poderia ter:
então, caramba, você mentiu com sucesso, certo? Bem, sim e não ... Considere que usar isso como um exploit significaria usar sua instância BadFoo como um argumento para um método em algum lugar, que espera provavelmente um
object
ou um tipo de base comum para uma hierarquia de objetos. Algo assim:mas
CheckIfInt(foo)
imprime "não é um int".Então, basicamente (de volta ao seu exemplo), você só poderia realmente explorar seu "tipo mentiroso" com código que alguém escreveu em sua
IFoo
interface, o que é muito explícito sobre o fato de ter umGetType()
método "personalizado" .Apenas se GetType () fosse virtual no objeto, você seria capaz de criar um tipo "mentiroso" que poderia ser usado com métodos como o
CheckIfInt
acima para criar confusão em bibliotecas escritas por outra pessoa.fonte
Existem duas maneiras de ter certeza sobre o tipo:
Use
typeof
no tipo que não pode ser sobrecarregadoLance a instância para um
object
e chame oGetType()
Métodofonte
typeof
em um método que só obtém umIFoo badFoo
como parâmetro?typeof
não pode ser aplicado a instâncias de uma classe que é o que precisamos fazer aqui. Sua única opção éGetType()
.BadFoo
", mas não "obtêm o tipo de variávelbadFoo
".Não, você não pode fazer GetType mentir. Você está apenas introduzindo um novo método. Apenas o código que conhece esse método o chamará.
Você não pode, por exemplo, fazer com que o código de terceiros ou de estrutura chame seu novo método GetType em vez do real, uma vez que esse código não sabe que seu método existe e, portanto, nunca o chamará.
No entanto, você pode confundir seus próprios desenvolvedores com tal declaração. Qualquer código que seja compilado com sua declaração e que use parâmetros ou variáveis digitadas como IFoo ou qualquer tipo derivado disso, de fato, usará seu novo método. Mas, uma vez que isso afeta apenas o seu próprio código, não impõe realmente uma "ameaça".
Se você deseja fornecer uma descrição de tipo personalizado para uma classe, isso deve ser feito usando um Descritor de Tipo Personalizado , talvez anotando sua classe com um TypeDescriptionProviderAttribute . Isso pode ser útil em algumas situações.
fonte
Bem, na verdade não é já um tipo que pode estar em
GetType
: qualquer tipo anulável.Este código :
saídas
True
.Na verdade, não
int?
é quem está mentindo, apenas o elenco implícito seobject
transformaint?
em um boxeint
. Mas, no entanto, você não pode dizerint?
a partir deint
comGetType()
.fonte
GetType()
produz um resultado um tanto estranho. Na verdade, perguntei a vários colegas se um não sombreadoGetType()
pode retornar algo que difere do tipo de tempo de execução do objeto real. A resposta de todos foi 'não'.Eu não acho que vá, já que todo código de biblioteca que chama GetType irá declarar a variável como 'Objeto' ou como um tipo genérico 'T'
O seguinte código:
estampas:
A única vez que este tipo de código resultará em cenários ruins é em seu próprio código, onde você declara o tipo de parâmetro como IFoo
fonte
O pior que pode acontecer, tanto quanto posso dizer, é enganar programadores inocentes que usam a classe envenenada, por exemplo:
Se
myInstance
for uma instância de uma classe como a que você descreve na pergunta, ela será tratada apenas como tipo desconhecido.Portanto, minha resposta é não, não consigo ver nenhuma ameaça real aqui.
fonte
Object.GetType()
é distinto deSomeUserdefinedInterfaceClassOrStruct.GetType()
. Só que, se você usar odynamic
tipo, nunca saberá o que acontecerá no momento da vinculação. Portanto, você deve usardynamic x = expression; ... Type t = ((object)x).GetType();
em casos como esse.Você tem algumas opções se quiser jogar pelo seguro contra esse tipo de hack:
Lançar para o objeto primeiro
Você pode chamar o
GetType()
método original primeiro convertendo a instância para umobject
:resulta em:
Usar método de modelo
Usar este método de modelo também fornecerá o tipo real:
fonte
Existe uma diferença entre
object.GetType
eIFoo.GetType
.GetType
é chamado em tempo de compilação em objetos desconhecidos e não em interfaces. No seu exemplo, com saídabadFoo.GetType
é esperado bahaviour, porque você sobrecarrega o método. A única coisa é que outros programadores podem se confundir com esse comportamento.Mas se você usá-
typeof()
lo, o tipo será o mesmo e você não poderá sobrescrevertypeof()
.Além disso, o programador pode ver em tempo de compilação, qual método
GetType
ele invoca.Então, para sua pergunta: este padrão não pode representar uma ameaça confiável, mas também não é o melhor estilo de codificação.
fonte
badFoo.GetType()
É um comportamento esperado, porqueGetType
estava sobrecarregado.