使用枚举来选择要实例化的类

我有一个枚举,我想与dto联系:

public enum DtoSelection { dto1, dto2, dto3, } 

此枚举中有108个值和值。

我为这些dto中的每一个都有一个dto对象:

  public class dto1 : AbstractDto { public int Id { get; set; } //some stuff specific to this dto } 

我正在尝试创建一个方法(最终是一个服务),它将返回一个与所讨论的dto相关联的类型的新dto对象:

  private AbstractDto(int id) { if (id == DtoSelection.Dto1.ToInt()) //extension method I wrote for enums return new Dto1(); if (id == DtoSelection.Dto2.ToInt()) return new Dto2(); } 

显然我不想这样做108次。 无论出于何种原因,我的大脑只是遗漏了一些明显 处理这个问题的最佳方法是什么。

只要在与AbstractDto相同的命名空间中定义Dto类,此类就可以执行您想要的操作(如果不是,则需要调整它):

鉴于以下枚举和类:

 public enum DtoSelection { Dto1, Dto2, Dto3, } public abstract class AbstractDto { } public class Dto1 : AbstractDto { } public class Dto2 : AbstractDto { } public class Dto3 : AbstractDto { } 

这种方法将解决它们:

 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); } } 

使用Activator.CreateInstance方法并将其传递给枚举的ToString值。

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

我会使用funcs字典。

 Dictionary> dictionary = new Dictionary> { {DtoSelection.dto1, () => new dto1()} }; var dto = dictionary[DtoSelection.dto1](); 

尝试使用Activator.CreateInstance

 return (AbstractDto)Activator.CreateInstance (Type.GetType(((DtoSelection)id).ToString(), true, true); 

或者,有点作弊,你可以使用一些代码生成:

 public static string GenerateValues() { StringBuilder sb = new StringBuilder(); sb.AppendLine("DtoSelection selection = (DtoSelection)id;"); sb.AppendLine("switch (selection)"); foreach (DtoSelection value in (DtoSelection[])Enum.GetValues(typeof(DtoSelection)) { sb.AppendLine("case DtoSelection." + value.ToString() + ":"); sb.AppendLine("return new " + value.ToString() + ";"); } } 

您应该使用IoC容器(Unity,StructureMap,NINject …)

Ioc允许:

  • 注册一个带有名称的类型,如下所示(取决于容器):

     Container.Register(DtoSelection.dto1.ToString()); 
  • 解决类型

     Container.Resolve(DtoSelection.dto1.ToString()); 

这将为您处理实例化的所有细节。

提供的其他解决方案被称为“穷人的IoC”。 不要重新发明轮子。

当然,你应该隐藏方法背后的容器:

  public void RegisterDto(DtoSelection dtoSelection) where TDto : AbstractDto, new() { Container.Register(dtoSelection.ToString()); } public TDto GetDto(DtoSelection dtoSelection) where TDto : AbstractDto { return Container.Resolve(dtoSelection.ToString()) as TDto; } 

注意:如果使用“构造函数注入”,则可以删除new()约束( 无参数构造函数的要求 )。 构造函数注入允许注册将用作带参数的构造函数的参数的值。 此参数可以是其他对象或抽象对象(接口,abstrac类)。 为此,您需要在contianer中注册此参数。

无论你选择哪种IoC都会比“穷人的IoC”有很多优势。

UPDATE

如果你想避免多次写入,大多数IoC COntainers也允许按名称注册,所以你可以这样注册:

  // iterate the DtoSelection Enum foreach(var e in Enum.GetValues(DtoSelection)) { DtoSelection dtoSel = (DtoSelection)e; int n = (int)dtoSel; Container.Register("Dto" + n, dtoSel.ToString()); } 

注意:第一个参数是类型名称(或完整类型名称)。 第二个是允许解析它的名称。

 public AbstractDto CreateDto(DtoSelection selection) { return (AbstractDto)Activator.CreateInstance(Type.GetType("Perhaps.Some.Qualifier.Here." + selection.ToString())); }