Creating Type Instances by Using ConstructorInfo

Once you have a System.Type object instance, you can use it to create an instance of the type it represents. This can be done by querying for a ConstructorInfo object. The ConstructorInfo class is used to discover the attributes of a constructor, and it provides access to constructor metadata. Most importantly, a ConstructorInfo instance can be used to invoke a type's constructor.

Before we start invoking constructors, let's discuss how you can get a hold of one of these powerful objects. The Type class provides two methods for retrieving ConstructorInfos: GetConstructors and GetConstructor.

Using the GetConstructors Method

The GetConstructors method comes in two flavors. The easiest flavor to use accepts no parameters and returns all of the public constructors defined for the type. You can iterate through the array of ConstructorInfo objects and then invoke the constructor you deem appropriate to use. We will discuss invoking the constructor shortly. Listing 13.7 demonstrates how to use GetConstructors to retrieve a list of all public constructors.

Listing 13.7.
C#
public class Type_GetConstructors {
  public int integer;
  public Type_GetConstructors() : this(0) {
  }

  public Type_GetConstructors(int anInt) {
    integer = anInt;
  }
}

public class Test {
  public static void Main() {
    Type t = typeof(Type_GetConstructors);
    ConstructorInfo[] cstors = t.GetConstructors();
    foreach(ConstructorInfo cstor in cstors) {
      MessageBox.Show(
        String.Format(
        "Found a {0} constructor that takes {1} parameters",
        (cstor.IsPublic ? "Public" : "Non-Public"),
        cstor.GetParameters().Length));
    }
  }
}

VB
Module Module1
    Sub Main()
        Dim t As Type
        Dim cstors As ConstructorInfo()
        Dim ndx As Int32
        Dim tgc As New Type_GetConstructors()

        t = tgc.GetType()
        cstors = t.GetConstructors()

        For ndx = 0 To cstors.Length - 1
            Dim visibility As String
            If cstors(ndx).IsPublic Then
                visibility = "Public"
            Else
                visibility = "Non-Public"
            End If

            MessageBox.Show( _
              String.Format( _
              "Found a {0} constructor that takes {1} parameters", _
               visibility, _
               cstors(ndx).GetParameters().Length))
        Next ndx
    End Sub

    Public Class Type_GetConstructors
        Public m_Int As Int32
        Public Sub New()
            m_Int = 0
        End Sub

        Public Sub New(ByVal int As Int32)
            m_Int = int
        End Sub
    End Class
End Module

The Type class also provides an overload of the GetConstructors method that takes one parameter. This parameter is of the type BindingFlags, an enumeration that controls the way in which the search for members and types is conducted by reflection. As we investigate reflection more in this chapter, you will see the BindingFlags enumeration appear again and again. This enumeration is defined with a FlagsAtribute attribute that allows a bitwise combination of its member values. Table 13.1 contains the list of BindingFlags values that are appropriate to pass to the GetConstructors method and how they affect the search.

Table 13.1. BindingFlags Members Relevant to the GetConstructors Method
MEMBERNAME DESCRIPTION
DefaultSpecifies no binding flag
InstanceSpecifies that instance constructors are to be included in the search
NonPublicSpecifies that nonpublic constructors are to be included in the search
PublicSpecifies that public constructors are to be included in the search
StaticSpecifies that static constructors are to be included in the search

Listing 13.8 demonstrates how to use GetConstructors to search for all constructors of a given type. This will include both static and instance constructors as well as both public and nonpublic constructors.

Listing 13.8.
C#
public class ConstructorInfo_GetConstructors {
  public static int staticInteger;
  public int integer;
  public ConstructorInfo_GetConstructors () : this(0) {
  }

  public ConstructorInfo_GetConsructors (int anInt) {
    integer = anInt;
  }

  private ConstructorInfo_GetConsructors (int x, int y) {
    integer = x;
    staticInteger = y;
  }

  static ConstructorInfo_GetConsructors () {
    staticInteger = 13;
  }

  public static void Main() {
    Type t = typeof(ConstructorInfo_GetConstructors);
    ConstructorInfo[] cstors =
      t.GetConstructors(BindingFlags.Instance | BindingFlags.Static |
                        BindingFlags.Public | BindingFlags.NonPublic);

    foreach (ConstructorInfo cstor in cstors) {
        MessageBox.Show(
        String.Format
        ("Found a {0} {1} constructor that takes {2} parameters",
          (cstor.IsStatic ? "Static" : "Instance"),
          (cstor.IsPublic ? "Public" : "Non-Public"),
          cstor.GetParameters().Length));
    }
  }
}

VB
Module Module1
    Public Class ConstructorInfo_GetConsructors
        Public Shared sharedInteger As Int32
        Public m_Int As Int32
        Public Sub New()
            m_Int = 0
        End Sub

        Public Sub New(ByVal anInt As Int32)
            m_Int = anInt
        End Sub

        Public Sub New(ByVal x As Int32, ByVal y As Int32)
            m_Int = x
            sharedInteger = y
        End Sub

        Shared Sub New()
            sharedInteger = 13
        End Sub
    End Class

    Sub Main()
        Dim t As Type
        Dim cstors As ConstructorInfo()
        Dim ndx As Int32
        Dim cigc = New ConstructorInfo_GetConsructors()
        t = cigc.GetType()
        cstors = t.GetConstructors(BindingFlags.Instance Or _
                                   BindingFlags.Static Or _
                                   BindingFlags.Public Or _
                                   BindingFlags.NonPublic)

        For ndx = 0 To cstors.Length - 1
            Dim visibility As String
            Dim isStatic As String

            If cstors(ndx).IsPublic Then
                visibility = "Public"
            Else
                visibility = "Non-Public"
            End If

            If cstors(ndx).IsStatic Then
                isStatic = "Static"
            Else
                isStatic = "Instance"
            End If

            MessageBox.Show( _
             String.Format( _
             "Found a {0} {1} constructor that takes {2} parameters", _
             visibility, _
             isStatic, _
             cstors(ndx).GetParameters().Length))
        Next ndx
    End Sub
End Module

Retrieving Individual ConstructorInfo Objects with GetConstructor

So far we have been searching for constructors based on visibility and scope. There will be times when you need to query for a constructor based on the number and type of parameters the constructor accepts. For instance, if you are building a custom serializer, you may need to search for a default constructor with which to construct an object being deserialized. The Type class provides the GetConstructor method to provide this functionality. The GetConstructor method returns a single ConstructorInfo object, or else null if the constructor could not be found. The method takes one parameter, a Type array that represents the number, order, and type of the parameters for the constructor to get. You can pass in an empty array of the type Type to get a constructor that takes no parameters. Do not pass in null for this; it would result in an ArgumentNullException. It is important to note that GetConstructor will look for public instance constructors and cannot be used to obtain a class initializer (static constructor). Listing 13.9 demonstrates how to use GetConstructor to query for a public instance constructor that takes zero parameters.

Listing 13.9.
C#
public class ConstructorInfo_GetConstructor {
  public static int staticInteger;
  public int integer;
  public ConstructorInfo_GetConstructor () : this(0) {
  }

  private ConstructorInfo_GetConstructor (int anInt) {
    integer = anInt;
  }

  static ConstructorInfo_GetConstructor () {
    staticInteger = 13;
  }

  public static void Main() {
    Type t = typeof(ConstructorInfo_GetConstructor);
    ConstructorInfo cstor = t.GetConstructor(new Type[0]);

    if(cstor == null)
      MessageBox.Show("No constructor found.");
    else
      MessageBox.Show
        ("Found a public instance constructor with no params");
  }
}

VB
Module Module1
    Public Class ConstructorInfo_GetConstructor
        Public Shared sharedInteger As Int32
        Public m_int As Int32
        Public Sub New()
            m_int = 0
        End Sub

        Public Sub New(ByVal anInt As Int32)
            m_int = anInt
        End Sub

        Shared Sub New()
            sharedInteger = 13
        End Sub
    End Class

    Sub Main()
        Dim t As Type
        Dim cstor As ConstructorInfo
        Dim empty() = New Type() {}
        Dim cigc As New ConstructorInfo_GetConstructor()

        t = cigc.GetType()
        cstor = t.GetConstructor(empty)

        If cstor Is Nothing Then
            MessageBox.Show("No constructor found.")
        Else
            MessageBox.Show _
              ("Found a public instance constructor with no params")
        End If
    End Sub
End Module

Creating Object Instances with the ConstructorInfo Class

Now that we know how to find a ConstuctorInfo, we are ready to use it to create an object instance. The ConstructorInfo class provides the Invoke method to invoke the constructor it represents. The Invoke method takes one parameter, an array of objects that represent values of the parameters to be passed to the constructor. The values should match the number, type, and order of the parameters for the constructor reflected by the ConstructorInfo object. Before calling the constructor, Invoke verifies that the parameters are valid. If the constructor takes no parameters, then you should pass in an empty array of objects. The ConstructorInfo method returns a reference to an object, so you must cast it to the correct type. Listing 13.10 code shows how to find a specific constructor, invoke the constructor, and inspect the new object instance.

Listing 13.10.
C#
public class ConstructorInfo_Invoke {
  public int integer;
  public string str;

  public ConstructorInfo_Invoke () : this(0, string.Empty) {
  }

  public ConstructorInfo_Invoke (int int1, string str1) {
    integer = int1;
    str = str1;
  }

  public static void Main() {
    Type[] ts = {typeof(int), typeof(string)};
    Type t = typeof(ConstructorInfo_Invoke);
    ConstructorInfo cstor = t.GetConstructor(ts);

    if (cstor == null) {
      MessageBox.Show("Could not create the object instance");
      return;
    }
    object[] os = {13, "This object was created with reflection."};
    object objTest = cstor.Invoke(os);

    ConstructorInfo_Invoke test = objTest as ConstructorInfo_Invoke;
    if( test == null) {
      MessageBox.Show("Could not cast the object to it correct type");
      return;
    }

    MessageBox.Show("New ConstructorInfo_Invoke object created:
" +
                    "	integer: " + test.integer +
                    "
	str: " + test.str);
  }
}

VB
Module Module1
    Public Class ConstructorInfo_Invoke
        Public m_int As Int32
        Public str As String

        Public Sub New()
            m_int = 0
            str = String.Empty
        End Sub

        Public Sub New(ByVal anInt As Int32, ByVal aStr As String)
            m_int = anInt
            str = aStr
        End Sub
    End Class

    Sub Main()
        Dim t As Type
        Dim ts() = New Type() {0.GetType(), String.Empty.GetType()}
        Dim os() = New Object() { _
                     13, _
                     "This object was created with reflection"}
        Dim ret As Object
        Dim cstor As ConstructorInfo
        Dim cii As New ConstructorInfo_Invoke()

        t = cii.GetType()
        cstor = t.GetConstructor(ts)

  If cstor Is Nothing Then
            MessageBox.Show("Could not create the object instance")
            Return
        End If

        os(0) = 13
        os(1) = "This object was created with reflection"
        ret = cstor.Invoke(os)

        Dim test = CType(ret, ConstructorInfo_Invoke)
        If test Is Nothing Then
            MessageBox.Show _
              ("Could not cast the object to its " & _
               "correct type instance")
            Return
        End If

        MessageBox.Show("New ConstructorInfo_Invoke object created:"& _
                        Chr(13) & "integer: " & test.m_int & _
                        Chr(13) & "str: " & test.str)
    End Sub
End Module

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.223.239.226