Reflection in VB.NET

Reflection is a powerful feature in the .NET Framework that allows you to inspect the metadata of assemblies, modules, and types at runtime. This means you can programmatically discover information about classes, methods, properties, and fields, and even invoke them. This can be incredibly useful for building flexible, dynamic applications.

What is Reflection?

Reflection provides the ability to:

Key Classes for Reflection

The primary namespace for reflection is System.Reflection. Some of the most important classes include:

Getting Type Information

You can obtain a Type object in several ways:

1. Using GetType()

This is the most common way to get the type of an object instance:

Example:

Dim myObject As New List(Of String)()
            Dim objType As Type = myObject.GetType()
            Console.WriteLine($"Type name: {objType.Name}") ' Output: Type name: List`1
            Console.WriteLine($"Full type name: {objType.FullName}") ' Output: Full type name: System.Collections.Generic.List`1[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"

2. Using the TypeOf operator

This is useful when you know the type at compile time:

Example:

Dim myString As String = "Hello"
            Dim strType As Type = GetType(String)
            Console.WriteLine($"Type name: {strType.Name}") ' Output: Type name: String"

3. Loading an Assembly and Getting Types

You can load an assembly by its file path and then retrieve its types.

Example:

Imports System.Reflection
            Imports System.IO

            Try
                Dim assemblyPath As String = "YourAssembly.dll" ' Replace with the actual path
                If File.Exists(assemblyPath) Then
                    Dim assembly As Assembly = Assembly.LoadFrom(assemblyPath)
                    Dim types() As Type = assembly.GetTypes()

                    Console.WriteLine($"Types found in {Path.GetFileName(assemblyPath)}:")
                    For Each t As Type In types
                        Console.WriteLine($"- {t.FullName}")
                    Next
                Else
                    Console.WriteLine($"Assembly not found at: {assemblyPath}")
                End If
            Catch ex As Exception
                Console.WriteLine($"An error occurred: {ex.Message}")
            End Try

Discovering Members

Once you have a Type object, you can discover its members:

Listing Methods

Example:

Imports System.Reflection

            Dim strType As Type = GetType(String)
            Dim methods() As MethodInfo = strType.GetMethods()

            Console.WriteLine($"Methods of String type:")
            For Each method As MethodInfo In methods
                Console.WriteLine($"- {method.Name}")
            Next

Listing Properties

Example:

Imports System.Reflection

            Dim listType As Type = GetType(List(Of Integer))
            Dim properties() As PropertyInfo = listType.GetProperties()

            Console.WriteLine($"Properties of List(Of Integer) type:")
            For Each prop As PropertyInfo In properties
                Console.WriteLine($"- {prop.Name} ({prop.PropertyType.Name})")
            Next

Invoking Methods Dynamically

Reflection allows you to call methods even if you don't know their names or signatures at compile time.

Example:

Imports System.Reflection

            Dim calculatorType As Type = GetType(MyCalculator) ' Assuming MyCalculator class exists with an Add method
            Dim calculatorInstance As Object = Activator.CreateInstance(calculatorType)

            Dim addMethod As MethodInfo = calculatorType.GetMethod("Add", New Type() {GetType(Integer), GetType(Integer)})

            If addMethod IsNot Nothing Then
                Dim parameters() As Object = {5, 10}
                Dim result As Object = addMethod.Invoke(calculatorInstance, parameters)
                Console.WriteLine($"Result of dynamic method call: {result}") ' Output: Result of dynamic method call: 15"
            Else
                Console.WriteLine("Method 'Add' not found.")
            End If

            Public Class MyCalculator
                Public Function Add(ByVal a As Integer, ByVal b As Integer) As Integer
                    Return a + b
                End Function
            End Class

Use Cases for Reflection

Performance Considerations

Reflection is generally slower than direct method calls or property access because it involves runtime lookup and overhead. Use it judiciously, especially in performance-critical code paths. Caching MethodInfo or Type objects can mitigate some of this overhead.