使用枚举来选择要实例化的类
我有一个枚举,我想与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())); }