A coworker was working on some kind of base EntityBuilder class to use in his tests. One of the requirements of the EntityBuilder class was that it would need to automatically set the ID of an entity to a ‘real’ value (as in: not the default value of the type). The EntityBuilder would use some kind of IdGenerator based on the type of the ID of the entity. First of all, the example i’m gonna show is highly simplified and might not look like it makes much sense, but it’s only to illustrate some C# stuff with regards to generics and the dynamic keyword. So bear with me, and just focus on the language details ![]()
Suppose you’ve got something like this:
public abstract class Entity<TId>
{
public virtual TId Id { get; set; }
}
public interface IIdGenerator<TId>
{
TId GenerateId();
}
public class IntIdGenerator : IIdGenerator<int>
{
private static int lastIssuedId;
public int GenerateId()
{
return ++lastIssuedId;
}
}
public class GuidIdGenerator : IIdGenerator<Guid>
{
public Guid GenerateId()
{
return Guid.NewGuid();
}
}
The idea was to write the EntityBuilder somewhat along these lines:
public abstract class TestEntityBuilder<TEntity, TId> where TEntity : Entity<TId>
{
public TEntity Build()
{
var entity = CreateEntityWithDefaultProperties();
entity.Id = GetIdGeneratorFor(typeof(TId)).GenerateId();
return entity;
}
protected abstract TEntity CreateEntityWithDefaultProperties();
private IIdGenerator<TId> GetIdGeneratorFor(Type type)
{
if (type == typeof(int))
{
return new IntIdGenerator();
}
return new GuidIdGenerator();
}
}
Of course, that doesn’t even compile… you’ll get the following compiler errors:
error CS0266: Cannot implicitly convert type 'MyProject.IntIdGenerator' to 'MyProject.IIdGenerator<TId>'. An explicit conversion exists (are you missing a cast?)
error CS0266: Cannot implicitly convert type 'MyProject.GuidIdGenerator' to 'MyProject.IIdGenerator<TId>'. An explicit conversion exists (are you missing a cast?)
So, how exactly do you get this working with generics? That’s when he asked for my help, and i didn’t know the answer either… i’ve struggled with this exact problem in a few previous situations and i never really got a clean solution either. But then i thought “wait, can’t we just avoid the problems with generics through the dynamic keyword?”
We changed the code to look like this:
public abstract class TestEntityBuilder<TEntity, TId> where TEntity : Entity<TId>
{
public TEntity Build()
{
var entity = CreateEntityWithDefaultProperties();
entity.Id = GetIdGeneratorFor(typeof(TId)).GenerateId();
return entity;
}
protected abstract TEntity CreateEntityWithDefaultProperties();
private dynamic GetIdGeneratorFor(Type type)
{
if (type == typeof(int))
{
return new IntIdGenerator();
}
return new GuidIdGenerator();
}
}
We just changed the return type of the GetIdGeneratorFor method to ‘dynamic’, and the call to the GenerateId method is now a dynamic call instead of a normal method call. And it works. No messing around with generics voodoo, no (direct) usage of reflection either. Just clean code.
I’ll probably use this trick a lot more times in the future when i run into the limitations of generics ![]()