我有一个我想尝试与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次。无论出于何种原因,我的大脑只是遗漏了一些明显处理这个问题的最佳方法是什么。
答案 0 :(得分:4)
使用Activator.CreateInstance方法并将其传递给enum的ToString
值。
Type type = Type.GetType(DtoSelection.dto1.ToString());
var temp = Activator.CreateInstance(type);
答案 1 :(得分:4)
只要在与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);
}
}
答案 2 :(得分:1)
我会使用funcs字典。
Dictionary<DtoSelection, Func<AbstractDto>> dictionary =
new Dictionary<DtoSelection, Func<AbstractDto>>
{
{DtoSelection.dto1, () => new dto1()}
};
var dto = dictionary[DtoSelection.dto1]();
答案 3 :(得分:1)
尝试使用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() + ";");
}
}
答案 4 :(得分:1)
解决此问题的一种优雅方法是使用Attributes和一个基类。让我告诉你:
您必须创建一个基类。在您的示例中,可以是AbstractDto,如下所示:
public abstract class AbstractDto : Attribute
{
//code of AbstractDto
}
然后,我们需要创建一个自定义属性,该属性将用于每个Dto类,以确定与每个类对应的枚举。
public class DtoEnumAttribute : Attribute
{
public DtoSelection Enum { get; set; }
public DtoEnumAttribute(DtoSelection enum)
{
this.Enum = enum;
}
}
然后,我们应该用适当的枚举装饰每个子Dto。让我们为Dto1做一个例子:
[DtoEnum(DtoSelection.Dto1)]
public class Dto1 : AbstractDto
{
//code of Dto1
}
最后,您可以使用一种方法,该方法可以接收特定的枚举和过滤器,或者您需要的任何逻辑。以下代码将实例化从您定义的枚举排序的 AbstractDto 继承的每个类。您可以在Where子句上使用它,以仅返回与所需枚举匹配的类的实例。问我在这一点上是否需要帮助。
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 => ((EnumDtoAttribute)x.GetType().GetCustomAttributes(typeof(EnumDtoAttribute), false).FirstOrDefault()).Enum);
//If you have parameters on you Dto's, you might pass them to CreateInstance(t, params)
}
在 dtos 列表上,您将拥有所需的实例。 希望对您有帮助!
答案 5 :(得分:0)
您应该使用IoC容器(Unity,StructureMap,NINject ...)
Ioc允许:
使用名称注册一个类型,如下所示(取决于容器):
Container.Register<AbstractDto,Dto1>(DtoSelection.dto1.ToString());
解析类型
Container.Resolve<AbstractDto>(DtoSelection.dto1.ToString());
这将为您处理实例化的所有细节。
提供的其他解决方案被称为“穷人的IoC”。不要重新发明轮子。
当然,你应该隐藏方法背后的容器:
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;
}
注意:如果使用“构造函数注入”,则可以删除new()
约束(requirement of parameterless constructor)。构造函数注入允许注册将用作带参数的构造函数的参数的值。此参数可以是其他对象或抽象对象(接口,abstrac类)。为此,您需要在contianer中注册此参数。
无论你选择哪种IoC都会比“穷人的IoC”有很多优势。
<强>更新强>
如果您想避免多次写入,大多数IoC COntainer也允许按名称注册,因此您可以进行如下注册:
// 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());
}
注意:第一个参数是类型名称(或完整类型名称)。第二个是允许解决它的名称。
答案 6 :(得分:0)
public AbstractDto CreateDto(DtoSelection selection)
{
return (AbstractDto)Activator.CreateInstance(Type.GetType("Perhaps.Some.Qualifier.Here." + selection.ToString()));
}