【问题标题】:Cleanest way to create class from enum type?从枚举类型创建类的最简洁方法?
【发布时间】:2018-01-30 10:22:04
【问题描述】:

我有以下枚举和类:

public enum MyEnum
{
   MyType1,
   MyType2
}

public abstract class MyBaseClass
{
   public abstract MyEnum GetMyType();
}

public class MySubClass : MyBaseClass
{
   public override MyEnum GetMyType()
   {
      return MyEnum.MyType1;
   }
}

我想创建一个基于 GetMyType() 的 MySubClass 实例,但不需要将 MySubClass“注册”到某种处理程序(或者这是要走的路吗?)。我知道这可能很容易通过反射来完成(通过 Assembly 循环从 MyBaseClass 继承的类并检查它们的 MyType),但这是要走的路吗?

现在我正在做一些很长的事情:

public MyBaseClass CreateMyClass(MyEnum myEnum)
{
   if(myEnum == MyEnum.MyType1)
   {
      return new MySubClass();
   }
   else if(myEnum == MyEnum.MyType2)
   {
      return new MyOtherSubClass();
   }
}

这最终会导致我忘记手动添加新类。它将在测试中被捕获,但我宁愿根本不必添加类,因为已经提供了所需的所有信息。

欢迎所有关于最佳方法的建议。

【问题讨论】:

  • 用自定义属性(例如[ClassType(MyEnum.MyType1)])装饰类并通过反射检查?或者修改整个方法,为什么需要这个?
  • 如何将自定义属性应用于枚举成员,类型为要实例化
  • CodeCaster:在数据库中只存储枚举类型,不存储类信息,因此需要将枚举类型转换为类。亚历克斯,你能解释一下应用于枚举成员的自定义属性吗?
  • 泛型怎么样?您可以即时创建任何类型的MyBaseClass<T>
  • 抱歉 Nyerguds,我看不出这对我有什么帮助,因为我仍然需要确定要实例化什么。

标签: c# enums factory system.reflection


【解决方案1】:

您可以创建一个自定义属性来识别所需的枚举类。

public class MyCustomAttribute : Attribute
{
    public MyEnum EnumType { get; set; }
}

然后是枚举和类;

public enum MyEnum
{
    MyType1,
    MyType2
}
public class MyBaseClass
{

}
[MyCustomAttribute(EnumType = MyEnum.MyType1)]
public class MySubClass : MyBaseClass
{

}
[MyCustomAttribute(EnumType = MyEnum.MyType2)]
public class MyOtherClass : MyBaseClass
{

}

您可以使用Reflection 来确定与枚举相关的类。

private static Dictionary<MyEnum, Type> _myEnumDictionary = new Dictionary<MyEnum, Type>();

public MyBaseClass GetEnumClass(MyEnum enumType)
{
    if (!_myEnumDictionary.ContainsKey(enumType))
    {
        var enumClass = typeof(MySubClass).Assembly
            .GetTypes()
            .FirstOrDefault(x => x.GetCustomAttributes<MyCustomAttribute>()
                .Any(k => k.EnumType == enumType));
        if (enumClass == null)
        {
            throw new Exception("There is no declared class with the enumType" + enumType);
        }
        _myEnumDictionary.Add(enumType, enumClass);
    }
    return (MyBaseClass)Activator.CreateInstance(_myEnumDictionary[enumType]);
}

最后,你可以像这样获取相关类的实例;

var mySubClass = GetEnumClass(MyEnum.MyType1);
var myOtherClass = GetEnumClass(MyEnum.MyType2);
//There is no lookup here. It will get the Type from Dictionary directly.
var mySubClass2 = GetEnumClass(MyEnum.MyType1); 

此外,您可以使用静态 Dictionary&lt;MyEnum, Type&gt; 字典集合来防止每次查找。

【讨论】:

  • 谢谢!感觉就像我正在寻找的东西一样。你会说这比将属性放在枚举成员上更好吗?如果放置在枚举成员上,则每次实例化类都不需要“查找”。 (性能与设计?)
  • 您仍然需要查找,但我会将值缓存在 Dictionary&lt;MyEnum, Type&gt; 中以使其超级快速。
  • 嗯“是的”。在这种情况下,我们遍历 Assembly 中的所有类,而在“我的”建议中,类型直接从 Enum 中得知,这将导致(伪代码): return (MyBaseClass)Activator.CreateInstance(MyEnumType.GetAttr())
【解决方案2】:

我希望这个例子能解决你的问题。

public enum MyEnum
{
    Type1, Type2
}
public abstract class MyBaseClass
{
    public abstract MyEnum GetMyType();
}
public class MySubClass1 : MyBaseClass
{
    public override MyEnum GetMyType()
    {
        // implementation
    }
}
public class MySubClass2 : MyBaseClass
{
    public override MyEnum GetMyType()
    {
        // implementation
    }
}

所以,你有 MySubClass1MySubClass2 作为你的 MyBaseClass 的孩子。
这是你的方法。

    public MyBaseClass CreateMyClass(MyEnum myEnum)
    {
        var dict = new Dictionary<MyEnum, Type>();
        dict.Add(MyEnum.Type1, typeof(MySubClass1));
        dict.Add(MyEnum.Type2, typeof(MySubClass2));

        var type = dict.Where(x => x.Key == myEnum).Select(x => x.Value);
        var instance = Activator.CreateInstance(type.GetType());
        return (MyBaseClass)instance;
    }

让我简要解释一下。 我们只是在DictionaryEnumType 之间创建一个映射。
根据我们在参数中得到的EnumActivator 创建从映射中找到的类型的实例。

这里唯一的问题是,如果我们将MyBaseClass 的子类以外的任何类型放入dict 字典中,则会引发运行时异常。

---------------编辑----

如果你想完全避免映射,那么你可以将类型作为函数的string参数传递,并实现如下

ObjectType instance = 
 (ObjectType)Activator.CreateInstance("MyAssembly","MyNamespace." + argType);

【讨论】:

  • 这也会产生总是必须手动添加新类的问题。不会真正解决我的问题,只能把它移到别处。
  • 是的,但是我们必须为EnumType 保留映射。代码如何理解它?
  • @Whyser :Stormcloak 的答案看起来很简洁,但它也将映射放在其他地方
猜你喜欢
  • 1970-01-01
  • 2014-12-01
  • 2021-03-17
  • 2022-01-09
  • 2018-08-10
  • 1970-01-01
  • 1970-01-01
  • 2013-04-14
  • 1970-01-01
相关资源
最近更新 更多