Creating Type Instances by Using ConstructorInfoOnce 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
Using the GetConstructors Method
The
GetConstructors
method comes in two flavors. The
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
Table 13.1. BindingFlags Members Relevant to the GetConstructors Method
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 GetConstructorSo 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 ClassNow 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:\n" +
"\tinteger: " + test.integer +
"\n\tstr: " + 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
|