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.
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.
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.
MEMBER | NAME DESCRIPTION |
---|---|
Default | Specifies no binding flag |
Instance | Specifies that instance constructors are to be included in the search |
NonPublic | Specifies that nonpublic constructors are to be included in the search |
Public | Specifies that public constructors are to be included in the search |
Static | Specifies 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.
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 |
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.
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 |
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.
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 |
18.223.239.226