You need to test the type of an object.
Use the inherited Object.GetType method to obtain a Type for the object. In some situations, you can also use the is and as operators to test an object's type.
All types inherit the
GetType
method from the
Object
base class. As discussed in recipe 3.10, this method returns a
Type
reference representing the type of the object. The runtime maintains a single instance of
Type
for each type loaded and all references for this type refer to this same object. This means that you can compare two type references
// Create a new StringReader for testing.
Object someObject =
new StringReader("This is a StringReader");
// Test if someObject is a StringReader by obtaining and
// comparing a Type reference using the typeof operator.
if (typeof(System.IO.StringReader) == someObject.GetType()) {
// Do something
}
C# provides the
is
operator as a quick way to perform the same test as the
IsStringReader
method. In addition,
is
will return
true
if the
// Test if someObject is, or is derived from, a TextReader
// using the is operator.
if (someObject is System.IO.TextReader) {
// Do something
}
Both of these approaches require that the type used with the typeof and is operators be known and resolvable at compile time. A more flexible (but slower) alternative is to use the Type.GetType method to return a Type reference for a named type. The Type reference isn't resolved until run time, which causes the performance hit, but allows you to change the type comparison at run time based on the value of a string. The IsType method here returns true if an object is of a named type and uses the Type.IsSubclassOf method to test if the object is a subclass of the named type.
public static bool IsType(object obj, string type) {
// Get the named type, use case insensitive search, throw
// an exception if the type is not found.
Type t = Type.GetType(type, true, true);
return t == obj.GetType() obj.GetType().IsSubclassOf(t);
}
Finally, you can use the as operator to perform a safe cast of any object to a specified type. If the object can't be cast to the specified type, the as operator returns null . This allows you to perform safe casts that are easy to verify, but the compared type must be resolvable at run time. Here's an example:
// Use the "as" operator to perform a safe cast.
StringReader reader = someObject as System.IO.StringReader;
if (reader != null) {
// Do something with reader
}
| Tip |
The static method GetUnderlyingType of the System.Enum class allows you to retrieve the underlying type of an enumeration. |
You need to instantiate an object at run time using reflection.
Obtain a Type object representing the type of object you want to instantiate, call its GetConstructor method to obtain a System.Reflection.ConstructorInfo object representing the constructor you want to use, and execute the ConstructorInfo.Invoke method.
The first step in creating an object using reflection is to obtain a Type object that represents the type you want to instantiate. (See recipe 3.10 for details.) Once you have a Type instance, call its GetConstructor method to obtain a ConstructorInfo representing one of the type's constructors. The most commonly used overload of the GetConstructor method takes a Type array argument and returns a ConstructorInfo representing the constructor that takes the number, order, and type of arguments specified in the Type array. To obtain a ConstructorInfo representing a parameterless (default) constructor, pass an empty Type array (use the static field Type.EmptyTypes ); don't use null , or GetConstructor will throw a System.ArgumentNullException . If GetConstructor can't find a constructor with a signature that matches the specified arguments, it will return null .
Once you have the desired
ConstructorInfo
, call its
Invoke
method. You must provide an
object
array containing the arguments you want to pass to the constructor.
Invoke
instantiates the new object and returns an
object
reference to it, which you must cast to the appropriate type. The following code
// Obtain the Type for the StringBuilder class.
Type type = typeof(System.Text.StringBuilder);
// Create a Type[] containing Type instances for each
// of the constructor arguments - a string and an int.
Type[] argTypes = new Type[] {typeof(System.String), typeof(System.Int32)};
// Obtain the ConstructorInfo object.
ConstructorInfo cInfo = type.GetConstructor(argTypes);
// Create an object[] containing the constructor arguments.
object[] argVals = new object[] {"Some string", 30};
// Create the object and cast it to StringBuilder.
StringBuilder sb = (StringBuilder)cInfo.Invoke(argVals);
Reflection functionality is commonly used to implement factories in which you use reflection to instantiate concrete classes that either extend a common base class or implement a common interface. Often both an interface and a common base class are used. The abstract base class implements the interface and any common functionality, and then each concrete implementation extends the base class.
There's no mechanism to
using System;
using System.Reflection;
// A common interface that all plug-ins must implement.
public interface IPlugin {
string Description { get; set; }
void Start();
void Stop();
}
// An abstract base class from which all plug-ins must derive.
public abstract class AbstractPlugin : IPlugin {
// Hold a description for the plug-in instance
private string description = "";
// Sealed property to get the plug-in description.
public string Description {
get { return description; }
set { description = value; }
}
// Declare the members of the IPlugin interface as abstract.
public abstract void Start();
public abstract void Stop();
}
// A simple IPlugin implementation to demonstrate the PluginFactory class.
public class SimplePlugin : AbstractPlugin {
// Implement Start method.
public override void Start() {
Console.WriteLine(Description + ": Starting...");
}
// Implement Stop method.
public override void Stop() {
Console.WriteLine(Description + ": Stopping...");
}
}
// A factory to instantiate instances of IPlugin.
public sealed class PluginFactory {
public static IPlugin CreatePlugin(string assembly,
string pluginName, string description) {
// Obtain the Type for the specified plug-in.
Type type = Type.GetType(pluginName + ", " + assembly);
// Obtain the ConstructorInfo object.
ConstructorInfo cInfo = type.GetConstructor(Type.EmptyTypes);
// Create the object and cast it to StringBuilder.
IPlugin plugin = (IPlugin)cInfo.Invoke(null);
// Configure the new IPlugin
plugin.Description = description;
return plugin;
}
}
This statement will create an instance of SimplePlugin using the PluginFactory class.
IPlugin plugin = PluginFactory.CreatePlugin(
"CreateObjectExample", // Private assembly name
"SimplePlugin", // Plug-in class name
"A Simple Plugin" // Plug-in instance description
);
| Note |
The
System.Activator
class provides two
static
methods named
CreateInstance
and
CreateInstanceFrom
that instantiate objects based on
Type
objects or strings containing type
|