【问题标题】:C# dynamically instantiate Type from EnumC# 从 Enum 动态实例化 Type
【发布时间】:2020-04-01 21:13:04
【问题描述】:

我是 C# 初学者。我希望你对我有耐心。假设我有一个枚举

public enum Dogs
{
    Terrier,
    Poodle,
    Pitbull,
}

还有一些狗类

public class Terrier {
}

public class Poodle {
}

public class Pitbull {
}

出于某种原因,我想从它们的类型(枚举值)动态实例化每个类,

        foreach(Dogs d in Enum.GetValues(typeof(Dogs)))
        {
            // d myDog = new d();
            // "...is a variable but is used like a type"
        }

我也试过

var myDog = Activator.CreateInstance(d);
// "...cannot convert from namespace.Dogs to System.Type"

【问题讨论】:

  • 虽然您的 Enum 和您的类中的值具有相同的名称,但它们不是相同的对象或类型,这就是您的两次尝试失败的原因。由于您是 C# 新手,我建议您从 switch 语句开始,使用 Enum 值作为案例,并在每个案例中手动编写返回正确类型 Dog 的代码。 Activator.Instance 通常在您没有直接引用要构造的类型时使用,所以我会在这里避免使用它。

标签: c# types enums instantiation


【解决方案1】:

如果你真的想要它:

(typeof(Dogs)).Assembly.CreateInstance(d.ToString());

【讨论】:

    【解决方案2】:

    不要为此使用枚举。一个更明智的解决方案是一组类型:

    private static Type[] dogs =
    {
        typeof(Terrier),
        typeof(Poodle),
        typeof(Pitbull),
    }
    

    那么你仍然可以把它们都翻一遍:

    foreach (Type type in dogs)
    {
        Object dog = Activator.CreateInstance(type);
    }
    

    尽管除非您仅在其上使用 .ToString(),否则您可能希望为这些类提供一个通用接口或超类来继承(正如 rfmodulator 在他的回答中所说的那样),以便您实际上可以在结果对象上调用函数。如果这三个都继承自 Dog 超类,这使得它们共享一个共同的 Bark() 方法,你至少可以这样做:

    public abstract class Dog
    {
        String Bark();
    }
    
    public class Terrier : Dog
    {
        public override String Bark() { return "Woof!"; }
    }
    
    public class Poodle : Dog
    {
        public override String Bark() { return "Yap"; }
    }
    
    public class Pitbull : Dog
    {
        public override String Bark() { return "Whuff!"; }
    }
    

    ...所以你实际上可以从你的实例化对象中得到一些有用的东西:

    foreach (Type type in dogs)
    {
        Dog dog = (Dog)Activator.CreateInstance(type);
        Console.WriteLine(dog.Bark());
    }
    

    从设计的角度来看,此方法的唯一缺点是无法强制将Dog 的子类型只能放入Type[] dogs 数组中;从技术上讲,任何类型的对象都可以放在那里。所以程序员有责任不要把它搞砸。

    【讨论】:

    • 感谢您的回答 Nyerguds,完美运行!
    • 我实际上在我的一个程序中使用它来自动检测文件类型。它只是将文件数据读取到字节数组中,每种类型都尝试解释它并查看它是否与预期匹配,一旦找到匹配项,它就会返回正确的对象,并在其中加载文件:)
    【解决方案3】:

    Dogs.TerrierTerrier 不同。

    您可以按照以下方式执行您所描述的操作:

    为简单起见,我将让所有类都实现一个通用接口,IDog:

    public interface IDog { }
    
    public class Terrier : IDog
    {
    }
    
    public class Poodle : IDog
    {
    }
    
    public class Pitbull : IDog
    {
    }
    

    现在我们可以这样做了:

    IDog dog;
    foreach (Dogs d in Enum.GetValues(typeof(Dogs)))
    {
        switch (d)
        {
            case Dogs.Terrier:
                dog = new Terrier();
                break;
            case Dogs.Poodle:
                dog = new Poodle();
                break;
            case Dogs.Pitbull:
                dog = new Pitbull();
                break;
            default:
                throw new Exception("no such dog!");
        }
    
        Debug.WriteLine($"dog is {dog.GetType()}");
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-16
      • 1970-01-01
      • 2021-04-03
      • 2014-01-26
      • 2019-11-08
      相关资源
      最近更新 更多