You should use an IoC container (Unity, StructureMap, NINject...)
An Ioc Allows to:
Register a Type with name, like so (depends on the container):
Container.Register<AbstractDto,Dto1>(DtoSelection.dto1.ToString());
Resolve the Type
Container.Resolve<AbstractDto>(DtoSelection.dto1.ToString());
This will handle all the details of instantiation for you.
The other solutions offered are called "Poor man's IoC". Don't reinvent the wheel.
Of course, you should hide the container behind methods:
public void RegisterDto<TDto>(DtoSelection dtoSelection)
where TDto : AbstractDto, new()
{
Container.Register<AbstractDto,Dto1>(dtoSelection.ToString());
}
public TDto GetDto<TDto>(DtoSelection dtoSelection)
where TDto : AbstractDto
{
return Container.Resolve<AbstractDto>(dtoSelection.ToString()) as TDto;
}
NOTE: The new()
constraint (requirement of parameterless constructor) can be removed if you use "constructor injection". Constructor injection allow to register values that will be used as parameters for constructor with parameters. This parameter can be other objects or abstract objects (interfaces, abstrac classes). For this to work you need to register this parameters in the contianer.
Whatever IoC you choose will have a lot of advantages over the "Poor man's IoC".
UPDATE
If you want to avoid writing it many times, most IoC COntainers also allow to register by name, so you can do the registration like this:
// iterate the DtoSelection Enum
foreach(var e in Enum.GetValues(DtoSelection))
{
DtoSelection dtoSel = (DtoSelection)e;
int n = (int)dtoSel;
Container.Register<AbstractDto>("Dto" + n, dtoSel.ToString());
}
NOTE: The first parameter is the type name (or full type name). The second is the name that will allow to resolve it.