Sunday, September 02, 2007

Reflection on Generic, Part 3 - Instantiate Generic Type

In this post, we will look at how to use reflection to instantiate a generic type.
First, let start with an example of how to do it in the usual way without reflection.

static void Main(string[] args)
{
List<string> list = InstatiateList();
list.ForEach(delegate(string s) { Console.WriteLine(s); });
Console.ReadLine();
}

private static List<string> InstatiateList()
{
List<string> listOfString = new List<string>();
listOfString.Add("AAA");
listOfString.Add("BBB");
return listOfString;
}
The above code will print out
AAA
BBB

Now, lets do it the reflection way.
static void Main(string[] args)    
{
List<string> list = InstatiateListReflectionWay();
list.ForEach(delegate(string s) { Console.WriteLine(s); });
Console.ReadLine();
}
 
private static List<string> InstatiateListReflectionWay()
{
// Get the metadata for List_Of_T
Type t = typeof(List<>);
 
// Make a type definition for List_Of_String
Type[] typeArg = new Type[1] { typeof(string) };
Type listOfStringDef = t.MakeGenericType(typeArg);
 
// Get the method metadata for Add() method.
MethodInfo mi = listOfStringDef.GetMethod("Add");
 
// Create an instance of List_Of_String.
object listOfString = Activator.CreateInstance(listOfStringDef);
 
// Add two element to the list.
mi.Invoke(listOfString, new object[] { "CCC" });
mi.Invoke(listOfString, new object[] { "DDD" });
return (List<string>)listOfString;
}

The above code will print out:
CCC
DDD

Even when you use reflection, the runtime still give you strongly type checking protection against your code. To prove this, insert the following code before the return statement in InstatiateListReflectionWay().
mi.Invoke(listOfString, new object[] { 123 });

This time, when you run the code again, you will see an exception thrown.
Exception thrown.
Exception thrown when insert a number into list_of_string. Click to view in full size.

Labels: , ,

Reflection on Generic, Part 2 - Reflecting Type Parameter

In the previous post, you have know how to retrieve type metadata for a generic type. In this post, let's walk through how to retrieve metadata for the type parameter. Let's use the following code as example:
public interface IPrint
{
string Print();
}
 
public class PrintingDevice<T> where T: class, IPrint, new()
{
public T Device;
}
 
public class ValueGenericType<T> where T : struct
{
public T Value;
}
 
....
 
private static void DumpType(Type t)
{
Console.WriteLine("Is Generic Type : {0}", t.IsGenericType);
Console.WriteLine("Type Name : {0}", t.FullName);
 
Type[] genericArguments = t.GetGenericArguments();
 
Console.WriteLine("Number of type parameter : {0}", genericArguments.Length);
foreach (Type typeArg in genericArguments)
{
// Check whether the current type represent a Generic Parameter.
Console.WriteLine("Is Generic Parameter : {0}", typeArg.IsGenericParameter);
 
// Get the constraint specified for type parameter
GenericParameterAttributes attr = typeArg.GenericParameterAttributes;

if ((attr & GenericParameterAttributes.DefaultConstructorConstraint) !=
GenericParameterAttributes.None)
{
Console.WriteLine("Default constructor constraint specified.");
}
 
if ((attr & GenericParameterAttributes.ReferenceTypeConstraint) !=
GenericParameterAttributes.None)
{
Console.WriteLine("Reference type constraint specified.");
}
 
if ((attr & GenericParameterAttributes.NotNullableValueTypeConstraint) !=
GenericParameterAttributes.None)
{
Console.WriteLine("Value type constraint specified.");
}
 
Type[] typeConstraints = typeArg.GetGenericParameterConstraints();
if (typeConstraints.Length > 0)
{
foreach (Type typeConstraint in typeConstraints)
{
Console.WriteLine("Type Constraint : {0}", typeConstraint.FullName);
}
}
else
{
Console.WriteLine("No type constraint specified.");
}
}
}


Run the following code with PrintingDevice,
Type t = typeof(PrintingDevice<>);
DumpType(t);

and the outcome will be :
Is Generic Type : True
Type Name : GenericConstraint.PrintingDevice`1
Number of type parameter : 1
Is Generic Parameter : True
Default constructor constraint specified.
Reference type constraint specified.
Type Constraint : GenericConstraint.IPrint


Run the code again with ValueGenericType,
Type t = typeof(ValueGenericType<>);
DumpType(t);

and the outcome will be :
Is Generic Type : True
Type Name : GenericConstraint.ValueGenericType`1
Number of type parameter : 1
Is Generic Parameter : True
Default constructor constraint specified.
Value type constraint specified.
Type Constraint : System.ValueType


Type.GetGenericArguments() will return an array of type parameters specified for the generic type.

Type.IsGenericParameter will return true if the current type represent a type parameter. If the type represent a type parameter, then the type will have no name.

Type.GenericParameterAttributes will return the constraints specified for that type parameter.

Type.GetGenericParameterConstraints() will return an array of type that are specified as the constraint for the type parameter.

Labels: , ,

Reflection on Generic, Part 1

You can use reflection against generic type to get metadata information about a generic type as well as instantiate a generic type with type argument. In this post, I will walk you through how to retrieve metadata about a generic type.

To check whether a type is a generic type, you use the Type.IsGenericType property.
Let start with a simple example:
Type s = typeof(string);
// This will print False.
Console.WriteLine(s.IsGenericType);
// This will print System.String
Console.WriteLine(s.FullName);

Since System.String is not a generic type, it will print False. Now let's use an example with generic type:
Type t = typeof(List<>);
// This will print True.
Console.WriteLine(t.IsGenericType);
// This will print System.Collections.Generic.List`1.
Console.WriteLine(t.FullName);
 
Type d = typeof(Dictionary<,>);
// This will print True.
Console.WriteLine(d.IsGenericType);
// This will print System.Collections.Generic.Dictionary`2.
Console.WriteLine(d.FullName);

In the above example, both will print True. Note that to retrieve type metadata for a generic type, you need to use the <> after the generic type name to denote the number of type parameters specified for that generic type. The number of type parameters are part of the type signature. It is perfectly legal to declare the following:

class C1<Y> { ... }
class C1<Y,T> { ... }

Going back to the example, since List only has one type paratemer, I just specify <> to indicate I want to the List generic class with one type parameter. For Dictionary class take take two type parameter, I specify <,> to indicate I want the Dictionary generic class with two type parameter.

When print out the full name of the class, notice that there is a number at the end of the class name. The number is called Arity which indicate the number of type parameter that the generic type have.

Labels: , ,

Thursday, August 30, 2007

NET: Checking what is the type argument

The following code sample show how you can check what is the type of the type argument passed to instantiate the generic type.


public class TypeDisplayer<T>
{
public string GetTypeArgument() { return typeof(T).FullName; }
}
 
static void ShowGenericTypeArgument()
{
//This will print System.Int32.
TypeDisplayer<int> i = new TypeDisplayer<int>();
Console.WriteLine(i.GetTypeArgument());
 
//This will print System.String.
TypeDisplayer<string> s = new TypeDisplayer<string>();
Console.WriteLine(s.GetTypeArgument());
}

Labels: , ,

NET: Generic Constraint Type - Default Constructor Constraint Type

Default Constructor constraint allow you to specify that the type parameter must have a default/parameterless constructor. This is useful if you want to create a new object instance of the type argument.


public class DefaultConstructorGenericType<T> where T : new()
{
public T Value;
 
public DefaultConstructorGenericType()
{
Value = new T();
}
}
 
public class ClassWithDefaultCon
{
public ClassWithDefaultCon() {}
}

public class ClassB
{
public int a;
public ClassB(int v) { a = v;}
}
 
static void InstantiateDefault()
{
// This code will compile fine.
DefaultConstructorGenericType<ClassWithDefaultCon> vt =
new DefaultConstructorGenericType<ClassWithDefaultCon>();
 
// This code will give compile error
// because ClassB does not have default constructor
DefaultConstructorGenericType<ClassB> vt =
new DefaultConstructorGenericType<ClassB>();
}


In the above sample, DefaultConstructorGenericType can only accept a type argument that has a default constructor. where keyword is used to specify a generic constraint in C#. In the above code sample, I specify that type parameter T has to have default constructor (indicate by where T : new()).

Labels: , ,

Wednesday, August 29, 2007

NET: Generic Constraint Type - Inheritance Constraint Type

Inheritance type constraint allow you to specify that the type parameter must be derive from certain base class or interface. It is useful if you want to assume the type argument to be of certain type so that you can call method on the instance of the type argument. Visual Studio will give you full intellisense support.


public interface IPrint
{
void Print();
}
 
public class Printer : IPrint
{
public void Print()
{
// Do something
}
}
 
public class PhotoCopier
{
public void PhotoCopy()
{
// Do something.
}
}
 
public class DeviceWrapper<T> where T : IPrint
{
public T Device;
}
 
static void InstantiateDevice()
{
// This code will compile fine.
DeviceWrapper<Printer> vt =
new DeviceWrapper<Printer>();
 
// This code will give compile error
// because PhotoCopier is not derive from IPrint.
DeviceWrapper<PhotoCopier> vt2 =
new DeviceWrapper<PhotoCopier>();
}

In the above sample, DeviceWrapper can only accept a type argument that is derive from IPrint.
where keyword is used to specify a generic constraint in C#. In the above code sample, I specify that
type parameter T has to be derive from IPrint (indicate by where T : IPrint).


Visual Studio Intellisense support
Visual Studio Intellisense support.

Labels: , ,

NET: Generic Constraint Type - Reference Constraint Type

Reference type constraint allow you to specify that the type parameter must be of reference type.

class GenericReferenceType<T> where T : class
{
public T Value;
}
 
static void InstantiateRefType()
{
// This code will compile fine.
GenericReferenceType<System.Text.StringBuilder> vt =
new GenericReferenceType<StringBuilder>();
 
// This code will give compile error
//because Point is not reference type.
GenericReferenceType<System.Drawing.Point> vt2 =
new GenericReferenceType<System.Drawing.Point>();
}


In the above sample, GenericReferenceType can only accept a reference type as its type parameter.
where keyword is used to specify a generic constraint in C#. In the above code sample, I specify that
type parameter T has to be of reference type (indicate by where T : class).

Labels: , ,

NET: Introduction to Generic Constraint Type

Generic constraint allow you to specify constraint/rule that limit what .net type can be used as type argument when you instantiate a generic type.

In this post, I will show a short code sample of how to use the various generic constraint.
For more explaination about Generic Constraint, visit msdn

How to specify constraint value type


Value type constraint allow you to specify that the type parameter must be of value type.

class GenericValueType<T> where T : struct
{
public T Value;
}
 
static void InstantiateValueType()
{
// This code will compile fine.
GenericValueType<System.Drawing.Point> vt =
new GenericValueType<System.Drawing.Point>();
 
// This code will give compile error
//because StringBuilder is not value type.
GenericValueType<System.Text.StringBuilder> vt2 =
new GenericValueType<StringBuilder>();
}


where keyword is used to specify a generic constraint in C#. In the above code sample, I specify that type parameter T has to be of value type (indicate by where T : struct).

Labels: , ,

Sunday, December 25, 2005

C# 2.0 : Property Access Modifier

In C# 2.0, you can specified different access for your property getter and setter.

In the folloing example, your can specify the getter for your Name property to have public access, but your setter is protected, which is only accessible from derived class.


public string Name
{
get
{
return name;
}
protected set
{
name = value;
}
}

Labels:

Friday, December 23, 2005

C# 2.0 : ?? Operator

C# 2.0 introduce a new operator "??". Make no mistake, it is a double question mark.

This operator evaluate an expression and return the value of the expression if not null, else return a default value.

a ?? "default" is equivalent to :


if(a == null)
return "default";
else
return a;


Try the following example:

static void Main(string[] args)
{
string aa = "abcd";

// This will print "abcd".
Console.WriteLine("aa is {0}", aa ?? "default text");

aa = null;
// This will print "default text".
Console.WriteLine("aa is {0}", aa ?? "default text");
}


Coming up next : Visual Studio 2005 Debugger Visualizer.

Labels:

Thursday, September 15, 2005

C# Language Innovation. Must Watch!

Anders Hejlsberg has a great video on Channel 9 which show case the great innovation they have done on C# 3.0 and .NET Framework 3.0.

The Language Integrated Query (LINQ) and type inferencing capability is really impressive.

Anders Hejlsberg - LINQ

Labels:

Monday, October 18, 2004

C# Edit and Continue

Folks at Microsoft announced that Edit and Continue will be available for C# in VS 2005. What a great news!

http://blogs.msdn.com/somasegar/archive/2004/10/15/242853.aspx

Labels: