是否可以在枚举中保存类型(使用“typeof()”)?

Posted

技术标签:

【中文标题】是否可以在枚举中保存类型(使用“typeof()”)?【英文标题】:Is it possible to save a Type (using "typeof()") in an enum? 【发布时间】:2012-06-16 01:19:18 【问题描述】:

所以我在 XNA、C# 4.0 中创建一个游戏,我需要管理很多 PowerUps(在代码中它们都继承自类“PowerUp”),并处理 PowerUps 的后端管理我当前有一个枚举 PowerupEffectType,它为 PowerUp 的每个子类都有一个值。最终在代码中,我需要将 PowerupEffectType 转换为 Powerup 类型(Type 类,通常使用typeof([class name]) 实现)。

由于这是一个小组项目,我想尽可能地将 PowerupEffectType 的每个值与其对应的类 Type 结合起来,即:不只是期望我的其他程序员使用 switch 语句手动进行转换,并确保添加/expansions 稍后会在尽可能少的地方进行尽可能少的更改。我有几个选择,到目前为止我发现的最好的方法是创建枚举伪方法,将所有内容压缩为一个 switch 语句(我想要的 99%),这要归功于我在这里找到的一些技巧:@ 987654321@

但我正试图更进一步 - 我可以将 Type 保存在 enum 中吗? 我知道您可以将枚举保存为特定类型(链接:@987654322 @),但Type 不是其中之一。当前的选择是 byte、sbyte、short、ushort、int、uint、long 和 ulong。是否有任何可行的方法可以将 Type 转换为上述任何数据类型并返回?

明确一点,这是我希望我能做到的,我正在寻找一种方法:

// (Assuming 'LightningPowerup', 'FirePowerup', and 'WaterPowerup' are
// all declared classes that inherit from a single base class)

public enum PowerupEffectType

    LIGHTNING = typeof(LightningPowerup),
    FIRE = typeof(FirePowerup),
    WATER = typeof(WaterPowerup)

有什么办法可以做到这一点,还是我只是将一个已经完成 99% 的问题的解决方案过于复杂化了?

提前致谢!

【问题讨论】:

我不知道你想在这里完成什么作为你的最终目标,但它闻起来就像你应该使用虚拟方法而不是打开枚举来完成的事情。通常,您想要从枚举中获取类型的原因是枚举是否来自外部源,可能是数据库。但是,在这种情况下,您可能希望您的 switch 块实例化 powerup 类型,而不是为您提供相应的类对象。 【参考方案1】:

你不能将它作为枚举的 value 来做,但你可以在 attribute 中指定它:

using System;
using System.Runtime.CompilerServices;

[AttributeUsage(AttributeTargets.Field)]
public class EffectTypeAttribute : Attribute

    public Type Type  get; private set; 

    public EffectTypeAttribute(Type type)
    
        this.Type = type;
    


public class LightningPowerup 
public class FirePowerup 
public class WaterPowerup 

public enum PowerupEffectType

    [EffectType(typeof(LightningPowerup))]
    Lightning,
    [EffectType(typeof(FirePowerup))]
    Fire,
    [EffectType(typeof(WaterPowerup))]
    Water

然后您可以在执行时通过反射提取这些属性值。但是,我会亲自创建一个字典:

private static Dictionary<PowerupEffectType, Type> EffectTypeMapping =
    new Dictionary<PowerupEffectType, Type>

     PowerupEffectType.Lightning, typeof(LightningPowerup) ,
     PowerupEffectType.Fire, typeof(FirePowerup) ,
     PowerupEffectType.Water, typeof(WaterPowerup) 
;

不需要特殊的属性,不需要用繁琐的反射代码提取值。

【讨论】:

有趣...你说得对,字典肯定是最简单的方法,我只是想学习一些新技术,所以复杂的解决方案可能正是我正在寻找的.话虽如此,我不知道属性,这改变了事情。谢谢! 或在运行时创建一个静态字典,通过枚举属性的反射延迟初始化。可能是两全其美【参考方案2】:

这不是你所要求的。我发现 Jon 的属性方法是最好的。但是为什么不将它包装在扩展方法中呢?

public Type GetPowerupEffectType(this PowerupEffectType powerEffect)

    switch (powerEffect)
    
        case LIGHTNING:
            return typeof(LightningPowerup);
        case FIRE:
            return typeof(FirePowerup);
        case WATER:
            return typeof(WaterPowerup);
        default:
            return default(Type);
    

并称它为:

PowerupEffectType e = PowerupEffectType.WATER;
var t = e.GetPowerupEffectType();

【讨论】:

这几乎就是我现在所做的,除了它默认为“throw new NotImplementedException()”,以确保如果我的其他开发人员添加了一个枚举,他们必须将它添加到扩展 switch 语句也是如此。这是我想要的 99%,我只是在寻找将其构建到枚举声明本身中的技术。不过,谢谢! @KeithA45 是的,Keith,没错。这就是为什么我说 Jon 的第一种方法是我找到的最好的方法。【参考方案3】:

这样的事情怎么样?

您可以获得与枚举一样的类型安全性,以及到类型的隐式转换

public class PowerupEffectType

    private readonly Type _powerupType;

    public static implicit operator Type(PowerupEffectType powerupEffectType)
    
        return powerupEffectType._powerupType;
    

    private PowerupEffectType(Type powerupType)
    
        _powerupType = powerupType;
    

    public static readonly PowerupEffectType LIGHTNING = new PowerupEffectType(typeof(LightningPowerup));
    public static readonly PowerupEffectType FIRE = new PowerupEffectType(typeof(FirePowerup));
    public static readonly PowerupEffectType WATER = new PowerupEffectType(typeof(WaterPowerup));

【讨论】:

这绝对是最接近 OP 想要的。为了额外的好处,XML doc tag completionlist 可用于为这种类型提供枚举样式的自动完成——但不幸的是,仅在 VB 中,不适用于 C#。 令人印象深刻!我不确定我是否会使用它,但这确实教会了我一项新技术。从 PowerupEffectType 中获取 Type 的语法是什么?你能给出一个快速的代码示例吗? 只需转换为 'Type' (Type)PowerupEffectType.FIRE【参考方案4】:

您可以使用static Dictionary&lt;PowerupEffectType, Powerup&gt;。我相信这将是你正在寻找的那种“婚姻”。它将允许轻松枚举和访问。

【讨论】:

【参考方案5】:

您只能使用 Microsoft 文档中的数字类型。默认情况下,枚举中每个元素的基础类型是 int。您可以使用冒号指定另一个整数类型,如前面的示例所示。有关可能类型的完整列表,请参阅枚举。 Reference: Enumeration Types

【讨论】:

【参考方案6】:

对不起,我不太明白这一点,你到底想达到什么目的;你能给出代码摘录吗?我不确定为什么你不能在这里只使用继承,而枚举给你的类型继承却没有。我感觉你是在提出解决方案而不是问题,我可能完全错了,你能澄清一下你打算如何使用这些元信息吗?

我很困惑,您是在要求告诉您类型/类的实例类型的东西吗?您可以使用枚举来存储您所说的每种类型的类型列表,但您为什么要这样做呢?您说您不想让其他程序员使用 switch 语句,但是很抱歉,我看不到您将类型信息存储在...类型的某些枚举中会带来什么好处。每个实例都知道它是什么类型以及它可以做什么。

您将如何处理类型信息?如果这些类型都继承自一个基类型,那么可能它们具有通用功能,可以在 abstract 方法中为任何特殊情况处理指定,或者可能返回一个 Null Object 无事可做(或者可能只是做没有)。这样您就不必担心添加新类 - 因为它们必须具有必要的行为。我尽量避免使用Enums,除非在您实际枚举一组固定的任意值的情况下,它们是不灵活的。 Enums 必须维护,这非常困难(在实践中)。

【讨论】:

【参考方案7】:

我实际上认为您可能想看看依赖注入框架。

看起来您正试图让其他开发人员开发不同的组件,然后您试图最终将它们全部集成到代码库的一个中心位置。

几个值得关注的项目:

http://www.ninject.org/ http://docs.structuremap.net/ http://archive.msdn.microsoft.com/mef

【讨论】:

以上是关于是否可以在枚举中保存类型(使用“typeof()”)?的主要内容,如果未能解决你的问题,请参考以下文章

获取值类型标签的父枚举

怎么根据一个值获取它在枚举里的值?

Js 中 typeof 与 instanceof 的区别

c#中怎么将string转化为枚举

使用Enum.Prase及Enum.TryPrase时的注意事项

我可以在 C# 中从泛型类型转换为枚举吗?