Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/283.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用枚举选择要实例化的类_C#_Abstraction - Fatal编程技术网

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

C# 使用枚举选择要实例化的类,c#,abstraction,C#,Abstraction,我有一个试图与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关联的枚举:

 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次。不管出于什么原因,我的大脑只是缺少了一些明显的东西。最好的处理方法是什么

使用方法并将其enum的
传递给字符串

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

我会使用funcs字典

Dictionary<DtoSelection, Func<AbstractDto>> dictionary = 
        new Dictionary<DtoSelection, Func<AbstractDto>>
{
    {DtoSelection.dto1, () => new dto1()}
};

var dto = dictionary[DtoSelection.dto1]();
字典=
新词典
{
{DtoSelection.dto1,()=>newdto1()}
};
var dto=字典[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() + ";");
    }
}

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

给定以下枚举和类:

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

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

国际奥委会允许:

  • 使用名称注册类型,如下所示(取决于容器):


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

    解决这个问题的一种优雅方法是使用属性和一个基类。让我告诉你:

    public AbstractDto CreateDto(DtoSelection selection)
    {
        return (AbstractDto)Activator.CreateInstance(Type.GetType("Perhaps.Some.Qualifier.Here." + selection.ToString()));
    }
    
  • 必须创建基类。在您的示例中,可以是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 => ((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)
    
     }
    
    public void MethodToGetInstances()
    {
    IEnumerable dtos=typeof(AbstractDto)
    .Assembly.GetTypes()
    其中(t=>t.IsSubclassOf(typeof(AbstractDto))&&&!t.IsAbstract)
    .Select(t=>(AbstractDto)Activator.CreateInstance(t))
    .OrderBy(x=>((DtoEnumAttribute)x.GetType().GetCustomAttributes(typeof(DtoEnumAttribute),false).FirstOrDefault()).Enum);
    //如果Dto上有参数,可以将它们传递给CreateInstance(t,params)
    }
    
  • dtos列表中,您将拥有所需的实例。
    希望有帮助

    我很好奇这是否可行。首先,您可以使用
    开关改进
    if
    列表。你想使用反射吗?在一个枚举中有108个不同的dto对象背后的原因是什么?为什么不使用数组呢?除了一些脆弱的反射,您可以创建一个
    字典
    ,在启动时(比如在私有静态构造函数中)就可以用工厂方法填充它。然后就这样叫它
    myDict[(DtoSelection)id]()
    @ChrisSinclair你如何在不“做108次”的情况下填充这本词典?我正在努力避免写108次。我需要构建一个所有类型的字典。对于我来说,避免使用丑陋的
    开关非常有用,我喜欢这样。不过,对于每个dto,我必须这样做108次。@Robert,您可以在枚举的成员上创建一个循环,然后创建实例并将其添加到列表中,对于循环,请参见:这是过度杀戮,依我看。@newStackExchangeInstance为什么过度杀戮?您只需添加一个Nuget包,并编写几行代码,比编写自己的“穷人的IoC”要少。此外,你要避免犯错误或忘记细节。它将比您几乎可以实现的任何东西都更安全、更高效地工作。对我来说,过度杀戮就是重新发明轮子来解决一个已经解决的问题。。。可能会引入一些意想不到的错误。让我们看看,更复杂的是什么(因此也有错误):Activator.CreateInstance还是一个复杂的IoC框架?有些错误不是因为它的复杂性,而是因为它的成熟度和质量。大多数IoC设计良好,有很多单元测试,多年来一直在LoB应用程序的生产中工作。这意味着它不是马车。当您使用Activator.CreateInstance时,什么会失败?你如何控制它?你还需要考虑什么?这一切都是在成熟的IoC容器中解决的。不要期望某个东西不是错误的,因为它是“一条无辜的指令”。在您的代码中,如果用户传递了错误的id会发生什么?它会抛出TypeNotFoundException。你的生活中发生了什么?
    
     public abstract class AbstractDto : Attribute
     {
          //code of AbstractDto       
     }
    
     public class DtoEnumAttribute : Attribute
     {
         public DtoSelection Enum { get; set; }
    
         public DtoEnumAttribute(DtoSelection enum)
         {
             this.Enum = enum;
         }
      }
    
     [DtoEnum(DtoSelection.Dto1)]
     public class Dto1 : AbstractDto
     {
          //code of Dto1
     }
    
     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)
    
     }