Use an enum to select which class to instantiate

An elegant way of solving this is by using Attributes and one base class. Let me show you:

  1. You must create a base class. In your example, could be AbstractDto, like following:

     public abstract class AbstractDto : Attribute
     {
          //code of AbstractDto       
     }
    
  2. Then, we need to create a custom attribute that will be used on every Dto class to determine which enum corresponds to each class.

     public class DtoEnumAttribute : Attribute
     {
         public DtoSelection Enum { get; set; }
    
         public DtoEnumAttribute(DtoSelection enum)
         {
             this.Enum = enum;
         }
      }
    
  3. Then we should decorate every child Dto with its proper enum. Let's do an example for Dto1:

     [DtoEnum(DtoSelection.Dto1)]
     public class Dto1 : AbstractDto
     {
          //code of Dto1
     }
    
  4. Finally, you can use a method that can receive an specific enum and filter, or whatever logic you need. The following code will instantiate every class that inherit from AbstractDto ordered by the Enum that you have defined. You can use it on a Where clause to return only the instance of the class that matches the enum that you want. Ask me if you need help on this point.

     public void MethodToGetInstances()
     {
            IEnumerable<AbstractDto> dtos = typeof(AbstractDto)
                .Assembly.GetTypes()
                .Where(t => t.IsSubclassOf(typeof(AbstractDto)) && !t.IsAbstract)
                .Select(t => (AbstractDto)Activator.CreateInstance(t))
                .OrderBy(x => ((DtoEnumAttribute)x.GetType().GetCustomAttributes(typeof(DtoEnumAttribute), false).FirstOrDefault()).Enum);
    
            //If you have parameters on you Dto's, you might pass them to CreateInstance(t, params)
    
     }
    

On the dtos list, you will have the instances that you want. Hope it helps!


Use Activator.CreateInstance method and pass it enum's ToString value.

Type type = Type.GetType(DtoSelection.dto1.ToString());
var temp = Activator.CreateInstance(type);

This class will do what you want as long as the Dto classes are defined in the same namespace as AbstractDto (you'll need to tweak it if not):

Given the following enums and classes:

public enum DtoSelection
{
    Dto1,
    Dto2,
    Dto3,
}

public abstract class AbstractDto
{
}

public class Dto1 : AbstractDto
{
}

public class Dto2 : AbstractDto
{
}

public class Dto3 : AbstractDto
{
}

This method will resolve them:

public static class DtoFactory
{
    public static AbstractDto Create(DtoSelection dtoSelection)
    {
        var type = Type.GetType(typeof(AbstractDto).Namespace + "." + dtoSelection.ToString(), throwOnError: false);

        if (type == null)
        {
            throw new InvalidOperationException(dtoSelection.ToString() + " is not a known dto type");
        }

        if (!typeof(AbstractDto).IsAssignableFrom(type))
        {
            throw new InvalidOperationException(type.Name + " does not inherit from AbstractDto");
        }

        return (AbstractDto)Activator.CreateInstance(type);
    }
}

Tags:

C#

Abstraction