Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.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#_Oop_Design Patterns - Fatal编程技术网

C# 如何使用枚举解析类类型

C# 如何使用枚举解析类类型,c#,oop,design-patterns,C#,Oop,Design Patterns,我的项目中有一组类(遵循策略模式)。在main函数中,我从服务器接收一个enum值,并在此基础上创建一个基类类型的对象 我使用switch/case语句来实现这一点。我在某处读到,开/闭原则不允许在添加新类时打开函数来添加新的case语句 我正在考虑使用Activator.CreateInstance()。它有什么缺点吗 是否有其他方法从枚举类型创建对象 添加下面的示例,即使它不是一个成熟的战略模式 abstract public class Mammal { public abstrac

我的项目中有一组类(遵循策略模式)。在main函数中,我从服务器接收一个enum值,并在此基础上创建一个基类类型的对象

我使用switch/case语句来实现这一点。我在某处读到,开/闭原则不允许在添加新类时打开函数来添加新的case语句

我正在考虑使用
Activator.CreateInstance()
。它有什么缺点吗

是否有其他方法从枚举类型创建对象

添加下面的示例,即使它不是一个成熟的战略模式

abstract public class Mammal
{
   public abstract void MakeSound()
}

class Cat:Mammal
{      
    public override  void MakeSound()
    {
        Console.WriteLine("Meow");        
    }    
}

class Dog:Mammal
{

    public override void MakeSound()
    {
         Console.WriteLine("Bow");        
    }    
}

Main()
{

    MammalTypes mammalType = RecieveValueFromServer();
    Mammal mammalBase
    switch(mammalType) // need to make this dynamic depending upon Enum type
    {
        case MammalTypes.Cat:mammalBase = new Cat()
                             break;
        case MammalTypes.Dog:mammalBase = new Dog()
                             break;            
    }

    mammalBase.MakeSound()
}

可以使用从枚举类型到函数的字典。这些函数用于创建策略对象:

public delegate Strategy StrategyFactory();
var strategyFactories = new Dictionary<MyEnum, StrategyFactory>();

工厂函数需要以某种方式添加到字典中。为此,您可以公开register(也可能是unregister)方法

您可以创建一个属性,该属性采用枚举值表示的类型,并将其应用于枚举字段,如下所示:

enum MyEnum {
   [Creates(typeof(FooStrategy))]
   Foo,
   [Creates(typeof(BarStrategy))]
   Bar,
   // etc.
}

[AttributeUsage(AttributeTargets.Field, Inherited=false, AllowMultiple=false)]
sealed class CreatesAttribute : Attribute {
    public Type TypeToCreate { get; private set; }
    public CreatesAttribute(Type typeToCreate) {
        TypeToCreate = typeToCreate;
    }

    public static IDictionary<T, Func<U>> GenerateLookup<T,U>() {
       var query = from field in typeof(T).GetFields()
                   let creates = field.GetCustomAttriubtes(typeof(CreatesAttribute), false) as CreatesAttribute[]
                   let method = CreationMethod(typeof(U)) // create your type here
                   let key = (T)field.GetValue(null)
                   select new { Key = key, Method = method };
       return q.ToDictionary(item => item.Key, item => item.Method);
    }
}
最后你会这样称呼它:

var myEnum = MyEnumType.Foo;
var strategy = myEnum.CreateInstance();
// use your strategy

这将防止您违反打开/关闭原则,并允许您添加所需的任意多个类,并且只更改枚举,该枚举可以变得足够通用,以便直接从枚举值创建策略的实例。

实现真正OCP的一种方法可能是:

定义一个抽象方法
Is
,强制哺乳动物的每个具体亚型指定它是否适合枚举的给定值:

abstract public class Mammal
{
    public abstract void MakeSound();

    public abstract bool Is(MammalTypes mammalType);
}
子类中Is的实现如下所示:

class Cat : Mammal
{
    // other specific members

    public override bool Is(MammalTypes mammalType)
    {
        return mammalType == MammalTypes.Cat;
    }
}

class Dog : Mammal
{
    // other specific members

    public override bool Is(MammalTypes mammalType)
    {
        return mammalType == MammalTypes.Dog;
    }
}
完成此操作后,我们现在可以创建一个哺乳动物工厂类,当给定哺乳动物枚举值时,该类将扫描可用类,当找到匹配项时,它将返回该类的实例:

public class MammalFactory
{
    private readonly IEnumerable<Type> _mammalTypes;

    public MammalFactory()
    {
        var currentAssembly = Assembly.GetExecutingAssembly();

        _mammalTypes = currentAssembly.GetTypes()
            .Where(t => typeof(Mammal).IsAssignableFrom(t) && !t.IsAbstract);
    }

    public Mammal Create(MammalTypes mammalType)
    {
        return _mammalTypes
            .Select(type => CreateSpecific(type, mammalType))
            .First(mammal => mammal != null);
    }

    public Mammal CreateSpecific(Type type, MammalTypes mammalEnumType)
    {
        var mammalInstance = (Mammal)Activator.CreateInstance(type);

        return mammalInstance.Is(mammalEnumType) ? mammalInstance : null;
    }
}
这完全符合OCP。只需创建一个新的哺乳动物类,它就可以自动连接并准备在应用程序中使用。(无需修改应用程序中的任何其他内容,枚举本身除外)

这种方法存在一些问题:

  • 它只扫描当前正在执行的程序集中的哺乳动物类型
  • 每次需要测试该类型是否合适时,它都必须创建一个哺乳动物实例
虽然这些问题可以解决,但仍然存在一个问题:复杂性

这很复杂,因为:

  • 我们已经将所需的代码量增加了一倍
  • 自动布线可能会让项目新手感到困惑
我认为结论是:设计模式不是严格的规则。仅仅为了符合给定的设计而做一些事情是不值得的。
相反,我们必须务实,在模式一致性和有用性/简单性/可读性之间找到完美的平衡。这在很大程度上取决于我们试图解决的问题,在许多情况下,它很可能是您在问题中提出的
开关
语句。

它不是面向对象的。基类不应该知道它的派生类。很难想象你做了什么。请将您编写的代码添加到问题中。
class Cat : Mammal
{
    // other specific members

    public override bool Is(MammalTypes mammalType)
    {
        return mammalType == MammalTypes.Cat;
    }
}

class Dog : Mammal
{
    // other specific members

    public override bool Is(MammalTypes mammalType)
    {
        return mammalType == MammalTypes.Dog;
    }
}
public class MammalFactory
{
    private readonly IEnumerable<Type> _mammalTypes;

    public MammalFactory()
    {
        var currentAssembly = Assembly.GetExecutingAssembly();

        _mammalTypes = currentAssembly.GetTypes()
            .Where(t => typeof(Mammal).IsAssignableFrom(t) && !t.IsAbstract);
    }

    public Mammal Create(MammalTypes mammalType)
    {
        return _mammalTypes
            .Select(type => CreateSpecific(type, mammalType))
            .First(mammal => mammal != null);
    }

    public Mammal CreateSpecific(Type type, MammalTypes mammalEnumType)
    {
        var mammalInstance = (Mammal)Activator.CreateInstance(type);

        return mammalInstance.Is(mammalEnumType) ? mammalInstance : null;
    }
}
var mammalFactory = new MammalFactory();

var guessWhatMammal = mammalFactory.Create(MammalTypes.Cat);