Можно ли сохранить тип (используя "typeof()" ) в перечислении?

Итак, я создаю игру в XNA, С# 4.0, и мне нужно управлять множеством PowerUps (которые в коде все наследуются от класса "PowerUp" ), а также для управления внутренним управлением PowerUps я в настоящее время имеет enum, PowerupEffectType, со значением для каждого дочернего класса PowerUp. В конце концов, в коде мне нужно сделать преобразования из PowerupEffectType в тип Powerup (класса Type, достигнутого обычно с помощью typeof([class name])).

Так как это групповой проект, я хочу жениться на каждом значении PowerupEffectType на его соответствующий тип класса, а также, возможно: т.е. не просто ожидать, что мои другие программисты будут использовать операторы switch для выполнения преобразования вручную, и убедитесь, что дополнения/расширения в дальнейшем предполагают как можно меньше изменений в максимально возможном количестве мест. У меня есть несколько вариантов этого, и лучшее, что я обнаружил до сих пор, это создание псевдо-методов enum, которые конденсируют все до одного оператора switch (99% от того, что я хочу), благодаря некоторым советам, которые я нашел здесь: http://msdn.microsoft.com/en-us/library/bb383974.aspx

Но я пытаюсь сделать это еще на один шаг - могу сохранить Type в enum? Я знаю, что вы можете сохранить перечисления как определенный тип (ссылка: http://msdn.microsoft.com/en-us/library/cc138362.aspx), но Type не является одним из них. Текущими выборами являются байт, sbyte, short, ushort, int, uint, long и ulong. Есть ли возможный способ сохранить преобразование a 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% завершена?

Спасибо заранее!

Ответ 1

Вы не можете сделать это как значение перечисления, но вы можете указать его в атрибуте:

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

Это не совсем то, о чем вы спрашиваете. Я считаю метод атрибута Джона лучшим. Но почему бы не обернуть его в метод расширения?

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

Ответ 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));
}

Ответ 4

Вы можете использовать static Dictionary<PowerupEffectType, Powerup>. Я считаю, что это будет "брак", который вы ищете. Это позволит легко перечислять и получать доступ.

Ответ 5

Вы можете использовать только числовые типы, как в документации Microsoft. По умолчанию базовый тип каждого элемента в перечислении - int. Вы можете указать другой целочисленный числовой тип, используя двоеточие, как показано в предыдущем примере. Полный список возможных типов см. В перечислении. Ссылка: типы перечислений

Ответ 6

Извините, я не совсем понимаю, чего вы на самом деле пытаетесь достичь; вы могли бы дать отрывок кода? Я не уверен, почему вы не можете просто использовать наследование здесь и что перечисление дает вам такого типа наследования. Мне кажется, что вы представляете решение, а не проблему, я могу быть совершенно неправ, не могли бы вы пояснить, как вы планируете использовать эту метаинформацию?

Я в замешательстве, вы просите что-то, что говорит вам тип экземпляра типа/класса? Вы можете использовать перечисление для хранения списка типов каждого типа, который вы говорите, но зачем вы хотите? Вы говорите, что не хотите, чтобы другие программисты использовали инструкции switch, но я сожалею, что не вижу, какую выгоду вы получаете от хранения информации о типе в каком-то перечислении... типа. Каждый экземпляр знает, что это за тип и что он может сделать.

Что вы будете делать с информацией о типе? Если все типы наследуются от базового типа, то, по-видимому, они имеют общую функциональность, которая может быть указана в методе abstract для обработки любого конкретного случая или, возможно, вернет Null Object, где нечего делать (или, может быть, просто сделать ничего). Таким образом, вам не нужно беспокоиться о добавлении новых классов, поскольку они должны иметь необходимое поведение. Я стараюсь избегать Enum, за исключением ситуаций, когда вы на самом деле перечисляете фиксированный набор произвольных значений, они негибкие. Enum, что очень сложно (на практике).

Ответ 7

Я действительно думаю, что вы можете взглянуть на инфраструктуру инъекций зависимостей.

Похоже, вы пытаетесь заставить других разработчиков работать с различными компонентами, а затем пытаетесь объединить их все в конце в одном центральном месте в базе кода.

Несколько проектов для просмотра: