Como verificar se um objeto é de um determinado tipo

102

Estou passando vários objetos para uma sub-rotina para executar o mesmo processo, mas usando um objeto diferente a cada vez. Por exemplo, em um caso estou usando um ListView e em outro caso estou passando um DropDownList.

Eu quero verificar se o objeto que está sendo passado é um DropDownList e executar algum código se for. Como eu faço isso?

Meu código até agora que não funciona:

Sub FillCategories(ByVal Obj As Object)
    Dim cmd As New SqlCommand("sp_Resources_Categories", Conn)
    cmd.CommandType = CommandType.StoredProcedure
    Obj.DataSource = cmd.ExecuteReader
    If Obj Is System.Web.UI.WebControls.DropDownList Then

    End If
    Obj.DataBind()
End Sub
Leah
fonte

Respostas:

160

No VB.NET, você precisa usar o GetTypemétodo para recuperar o tipo de uma instância de um objeto e o GetType()operador para recuperar o tipo de outro tipo conhecido.

Depois de ter os dois tipos, você pode simplesmente compará-los usando o Isoperador.

Portanto, seu código deve realmente ser escrito assim:

Sub FillCategories(ByVal Obj As Object)
    Dim cmd As New SqlCommand("sp_Resources_Categories", Conn)
    cmd.CommandType = CommandType.StoredProcedure
    Obj.DataSource = cmd.ExecuteReader
    If Obj.GetType() Is GetType(System.Web.UI.WebControls.DropDownList) Then

    End If
    Obj.DataBind()
End Sub

Você também pode usar o TypeOfoperador em vez do GetTypemétodo. Observe que isso testa se seu objeto é compatível com o tipo fornecido, não se é do mesmo tipo. Isso ficaria assim:

If TypeOf Obj Is System.Web.UI.WebControls.DropDownList Then

End If

Completamente trivial, picuinhas irrelevantes: Tradicionalmente, os nomes dos parâmetros são camelCased (o que significa que eles sempre começam com uma letra minúscula) ao escrever código .NET (seja VB.NET ou C #). Isso os torna fáceis de distinguir rapidamente de classes, tipos, métodos, etc.

Cody Gray
fonte
1
Obrigado pela sua resposta. Eu tentei esse código, mas na verdade a única coisa é que ele não funciona com o operador '='. Eu tive que mudar para 'É'. O erro que eu tive quando foi '=' foi "Operador '=' não está definido para os tipos 'System.Type' e 'System.Type'."
Leah
1
@Leah: Sim, sinto muito por isso. Parece que devo começar a prestar mais atenção ao escrever as respostas. TypeOfé provavelmente uma opção ainda mais simples, pelo menos em termos de legibilidade do código; Também atualizei a resposta com um exemplo disso.
Cody Gray
35
Existe uma diferença importante entre os dois, que é o que me levou a este post. A verificação TypeOf retornará True se o objeto for de uma classe que herda do tipo que você está verificando, enquanto GetType retornará True se for exatamente a mesma classe.
Abacus
Contraponto totalmente trivial e irrelevante: Mesmo que o VS CodeAnalysis reclame, ainda sinto que os nomes dos argumentos fazem parte da interface pública, assim como PascalCase em meu código.
Mark Hurd
Existe uma diferença de desempenho entre os dois? - E Select Case (Obj.GetType())com vários casos de teste Vs múltiplos IF TypeOf Obj is ...?
Luke T O'Brien
3

Mais alguns detalhes em relação à resposta de Cody Gray. Como demorei algum tempo para digeri-lo, pensei que pudesse ser útil para outras pessoas.

Primeiro, algumas definições:

  1. Existem TypeNames, que são representações de string do tipo de um objeto, interface, etc. Por exemplo, Baré um TypeName in Public Class Barou in Dim Foo as Bar. TypeNames podem ser vistos como "rótulos" usados ​​no código para informar ao compilador qual definição de tipo procurar em um dicionário, onde todos os tipos disponíveis seriam descritos.
  2. Existem System.Typeobjetos que contêm um valor. Este valor indica um tipo; da mesma forma Stringque um pegaria um texto ou Intum número, exceto que estamos armazenando tipos em vez de texto ou números. Typeos objetos contêm as definições de tipo, bem como seu TypeName correspondente.

Em segundo lugar, a teoria:

  1. Foo.GetType()retorna um Typeobjeto que contém o tipo da variável Foo. Em outras palavras, ele informa do que Fooé uma instância.
  2. GetType(Bar)retorna um Typeobjeto que contém o tipo para o TypeName Bar.
  3. Em alguns casos, o tipo ao qual um objeto foi Casté diferente do tipo a partir do qual um objeto foi instanciado pela primeira vez. No exemplo a seguir, MyObj é Integerconvertido em Object:

    Dim MyVal As Integer = 42 Dim MyObj As Object = CType(MyVal, Object)

Então, é MyObjdo tipo Objectou do tipo Integer? MyObj.GetType()dirá que é um Integer.

  1. Mas aí vem o Type Of Foo Is Barrecurso, que permite verificar se uma variável Fooé compatível com um TypeName Bar. Type Of MyObj Is Integere Type Of MyObj Is Objectambos retornarão True. Na maioria dos casos, TypeOf indicará que uma variável é compatível com um TypeName se a variável for desse tipo ou um tipo que deriva dele. Mais informações aqui: https://docs.microsoft.com/en-us/dotnet/visual-basic/language-reference/operators/typeof-operator#remarks

O teste abaixo ilustra muito bem o comportamento e o uso de cada uma das palavras-chave e propriedades mencionadas.

Public Sub TestMethod1()

    Dim MyValInt As Integer = 42
    Dim MyValDble As Double = CType(MyValInt, Double)
    Dim MyObj As Object = CType(MyValDble, Object)

    Debug.Print(MyValInt.GetType.ToString) 'Returns System.Int32
    Debug.Print(MyValDble.GetType.ToString) 'Returns System.Double
    Debug.Print(MyObj.GetType.ToString) 'Returns System.Double

    Debug.Print(MyValInt.GetType.GetType.ToString) 'Returns System.RuntimeType
    Debug.Print(MyValDble.GetType.GetType.ToString) 'Returns System.RuntimeType
    Debug.Print(MyObj.GetType.GetType.ToString) 'Returns System.RuntimeType

    Debug.Print(GetType(Integer).GetType.ToString) 'Returns System.RuntimeType
    Debug.Print(GetType(Double).GetType.ToString) 'Returns System.RuntimeType
    Debug.Print(GetType(Object).GetType.ToString) 'Returns System.RuntimeType

    Debug.Print(MyValInt.GetType = GetType(Integer)) '# Returns True
    Debug.Print(MyValInt.GetType = GetType(Double)) 'Returns False
    Debug.Print(MyValInt.GetType = GetType(Object)) 'Returns False

    Debug.Print(MyValDble.GetType = GetType(Integer)) 'Returns False
    Debug.Print(MyValDble.GetType = GetType(Double)) '# Returns True
    Debug.Print(MyValDble.GetType = GetType(Object)) 'Returns False

    Debug.Print(MyObj.GetType = GetType(Integer)) 'Returns False
    Debug.Print(MyObj.GetType = GetType(Double)) '# Returns True
    Debug.Print(MyObj.GetType = GetType(Object)) 'Returns False

    Debug.Print(TypeOf MyObj Is Integer) 'Returns False
    Debug.Print(TypeOf MyObj Is Double) '# Returns True
    Debug.Print(TypeOf MyObj Is Object) '# Returns True


End Sub

EDITAR

Você também pode usar Information.TypeName(Object)para obter o TypeName de um determinado objeto. Por exemplo,

Dim Foo as Bar
Dim Result as String
Result = TypeName(Foo)
Debug.Print(Result) 'Will display "Bar"
Ama
fonte