Insights from using Generics

Finally I’ve built code using Generics. Sure Generics has been around since .net 2.0. But my thing has been to code my commercial products. Peter’s Data Entry Suite had its origins in ASP.NET 1.0 and still can be compiled for ASP.NET 1.x customers. (There still are a few.) The new Versatile DataSources project allowed me to work with Generics and I had a blast. Yet I ran into some challenges that I’m sure everyone runs into. I figured I’d write about how I solved them.

Testing type compatibility (polymorphism)

The usual way to determine if an object is a specific type is through this syntax in C#:

if (objectinstance is type)

The “is” keyword does all of the work. Unfortunately this doesn’t work with generic types when you want to compare to the unbounded type. The unbounded type is the initial class declaration, like class MyClass<T>, where T has yet to be assigned. Its legal to test

if (myEntity is BaseEntity<Product>)

But if you want to test for BaseEntity<> without regard to Product, expect a compiler error:

if (myEntity is BaseEntity<>) // Illegal!

I found the solution here: http://stackoverflow.com/questions/457676/c-reflection-check-if-a-class-is-derived-from-a-generic-class. I used the answer posted on May 22.

It employs the Extension method concept, extending the System.Type class to offer HasGenericDefinition().

Use it like this:


Type objecttype = objectinstance.GetType();
if (objecttype.HasGenericDefinition(typeof(type<>)))

For example, to see if a MethodInfo object (describes a method using Reflection) has the return type of IEnumerable<>:

if (methodInfo.ReturnType.HasGenericDefinition(typeof(IEnumerable<>))

Also take from this example that the typeof() operator can be passed an unbounded type.

I would like to see something like this built into the .net framework and the C# language.

Typecasting to an unbounded type

Here’s some code that has a lot of problems.


public void TypeCasting(IEnumerable<> list) // illegal!
{
IEnumerable<> newlist = (IEnumerable<>) list.Clone();// illegal!
}

You cannot use unbounded types in all 3 locations shown above. If you want to share a type without regards to the bounded type, use a separate interface that does not use generics. The .net framework does this frequently: IEnumerable<> has IEnumerable; IQueryable<> has IQueryable.

Your own classes should define a non-generic interface too. For example:


public class MyGenericType<T> : IMyGenericType
{
}

The members of your generic type that need to be available to other consumers that are not interested in the bounded type should be declared in the interface.

For example:


public interface IMyGenericType
{
string Value { get; set; }
}
public class MyGenericType<T>:IMyGenericType
{
public string Value { get; set; }
}

Finally, the consumer method for MyGenericType would look like this:


public string UpdateText(IMyGenericType genType)
{
IMyGenericType newGenType = (IMyGenericType) genType.Clone(); // assumes Clone() is implemented
newGenType.Value = "Updated";
return newGenType.Value;
}
 
David Ebbo also offers a new solution using the C# Dynamic Type feature coming in .net 4.0. See http://blogs.msdn.com/davidebb/archive/2009/10/23/using-c-dynamic-to-call-static-members.aspx.
 

Instantiate objects through reflection

Let’s suppose you want to create an object of type List<T>, where T is determined at runtime. For example, the user passes in an object type to your function that creates the object.


public void CreateYourTypeAsList(Type myType)
{
}

 

It is illegal to pass a Type object to define the bounds on the generic type.

List<myType> list = new List<myType>(); // illegal!

You need to use Reflection to create your instance. Here’s the code:


public IList CreateYourTypeAsList(Type myType)
{
Type vGeneric = typeof(List<>);
Type vBounded = vGeneric.MakeGenericType(new Type[] { myType });
System.Reflection.ConstructorInfo vConstructor = vBounded.GetConstructor(new Type[] {});
return (IList) vConstructor.Invoke(new object[] { });
}

 This is how it works.

  1. Use the MakeGenericType() method, on System.Type, to create a bounded type. The parameter list takes the elements that normally go in the <> symbol. For List<T>, there is one parameter. For Dictionary<Key,Value>, there are two parameters.
  2. Use Reflection to get the constructor you will use to create this object. The System.Type.GetConstructor() method takes a list of types that exactly match the types of the desired constructor. In the above example, there are no parameters, leaving the Type[] array empty.
  3. Invoke the constructor, passing in values for its parameters.

Personally, I find this approach excessive and hope the C# language team gives us a simpler approach.

1 Comment

  • Since you're calling the parameterless constructor of the List class, you don't need to get and invoke the constructor; you can simply use Activator.CreateInstance:

    public IList CreateYourTypeAsList(Type myType)
    {
    Type vGeneric = typeof(List);
    Type vBounded = vGeneric.MakeGenericType(new Type[] { myType });
    return (IList)Activator.CreateInstance(vBounded);
    }

Comments have been disabled for this content.