Reflection in VB.NET

Reflection is a powerful feature of the .NET Framework that allows you to inspect the metadata of assemblies, modules, and types at runtime. It enables you to dynamically discover information about types, such as their properties, methods, events, and fields, and to invoke methods or access fields at runtime. This is particularly useful for building generic applications, such as serializers, object browsers, and data-binding frameworks.

Core Concepts

Reflection primarily involves the use of types from the System.Reflection namespace. Key types include:

  • Assembly: Represents an assembly. You can load assemblies dynamically and then examine their contents.
  • Type: Represents type declarations, such as classes, interfaces, arrays, value types, enums, and type parameters.
  • MethodInfo: Provides information about methods and allows their invocation.
  • PropertyInfo: Provides information about properties and allows their get/set operations.
  • FieldInfo: Provides information about fields and allows their get/set operations.
  • ConstructorInfo: Provides information about constructors and allows object instantiation.

Getting a Type

There are several ways to obtain a Type object:

  1. Using the GetType() method on an object instance.
  2. Using the GetType(String) method on the Type class, passing the fully qualified name of the type.
  3. Using the TypeOf...Is operator (for type checking).

Example of getting a type:


Imports System
Imports System.Reflection

Module ReflectionDemo

    Sub Main()
        ' Get Type from an object instance
        Dim myString As String = "Hello Reflection"
        Dim stringType As Type = myString.GetType()
        Console.WriteLine($"Type of myString: {stringType.FullName}")

        ' Get Type by name
        Dim dateTimeType As Type = Type.GetType("System.DateTime")
        If dateTimeType IsNot Nothing Then
            Console.WriteLine($"Type of DateTime: {dateTimeType.FullName}")
        Else
            Console.WriteLine("System.DateTime type not found.")
        End If

        ' Get Type from the current assembly
        Dim currentAssemblyType As Type = GetType(ReflectionDemo)
        Console.WriteLine($"Type of current module: {currentAssemblyType.FullName}")

    End Sub

End Module
                

Discovering Members

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

  • GetMembers(): Retrieves all public members of the current Type.
  • GetMethods(): Retrieves all public methods.
  • GetProperties(): Retrieves all public properties.
  • GetFields(): Retrieves all public fields.
  • GetConstructors(): Retrieves all public constructors.

You can also specify binding flags to retrieve non-public members or members declared on base types.

Invoking Methods

The MethodInfo object allows you to invoke methods on an instance of a type.

Example: Invoking a Method

This example shows how to get a method by name and invoke it.


Imports System
Imports System.Reflection

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

Module ReflectionInvokeDemo

    Sub Main()
        Dim calc As New MyCalculator()
        Dim calcType As Type = calc.GetType()

        ' Get the Add method
        Dim addMethod As MethodInfo = calcType.GetMethod("Add", New Type() {GetType(Integer), GetType(Integer)})

        If addMethod IsNot Nothing Then
            ' Invoke the method
            Dim result As Object = addMethod.Invoke(calc, New Object() {5, 10})
            Console.WriteLine($"Result of Add(5, 10): {result}") ' Output: 15
        Else
            Console.WriteLine("Add method not found.")
        End If
    End Sub

End Module
                    

Accessing Properties and Fields

Similar to methods, PropertyInfo and FieldInfo objects are used to get and set property/field values.

Example: Accessing Properties

This example demonstrates getting and setting a public property.


Imports System
Imports System.Reflection

Public Class Person
    Public Property Name As String
    Public Property Age As Integer
End Class

Module ReflectionPropertyDemo

    Sub Main()
        Dim person As New Person()
        Dim personType As Type = person.GetType()

        ' Get the Name property
        Dim nameProperty As PropertyInfo = personType.GetProperty("Name")
        If nameProperty IsNot Nothing Then
            nameProperty.SetValue(person, "Alice")
            Dim retrievedName As Object = nameProperty.GetValue(person)
            Console.WriteLine($"Person's Name: {retrievedName}") ' Output: Alice
        End If

        ' Get the Age property
        Dim ageProperty As PropertyInfo = personType.GetProperty("Age")
        If ageProperty IsNot Nothing Then
            ageProperty.SetValue(person, 30)
            Dim retrievedAge As Object = ageProperty.GetValue(person)
            Console.WriteLine($"Person's Age: {retrievedAge}") ' Output: 30
        End If
    End Sub

End Module
                    

Use Cases for Reflection

  • Serialization: Inspecting object state to save and load it.
  • Object Browsers and Designers: Dynamically displaying type information.
  • Data Binding: Connecting UI elements to object properties.
  • Testing Frameworks: Discovering and invoking test methods.
  • Plugin Architectures: Loading and interacting with external assemblies.

Performance Considerations

While powerful, reflection can be slower than direct member access. This is due to the overhead of dynamically looking up types and members at runtime. For performance-critical sections of code, consider caching reflection information or using direct access where possible. For typical application scenarios, the performance impact is often negligible.

Security Considerations

Reflection can bypass traditional access control. If you grant a user permission to use reflection, they might be able to access or invoke members that would normally be restricted. Therefore, use reflection cautiously, especially in security-sensitive applications.