Как создать метод расширения GetEnumValues ​​в Silverlight, который работает так же, как и в .NET?

Ниже приведен фрагмент кода, который я нахожу полезным в том, что я могу использовать его, чтобы быстро перевернуть круглые перечисления. CurrentEnum хранит ссылку на перечисление, которое использовалось для предоставления строк, в данном случае "Лысый", и оно может меняться.

То, что я пытаюсь сделать, это повторить ту же функциональность в Silverlight, которая не имеет функции GetEnumValues. Предпочтительным решением будет метод расширения, который можно использовать так же, как в моем примере ниже.

class Program
{
    enum Cats { Fluffy, Furry, Bald };
    enum Dogs { Big, Fat, Ugly };

    static Type CurrentEnum = typeof(Cats);

    static void Main(string[] args)
    {
        Int32 i = (Int32)Enum.Parse(CurrentEnum, "Bald", true);
        i = i == CurrentEnum.GetEnumValues().Length - 1 ? 0 : i + 1;
        String nextValue = CurrentEnum.GetEnumValues().GetValue(i).ToString();

        Console.WriteLine(nextValue);
        Console.ReadKey();
    }
}

UPDATE:

Вот что я решил сейчас:

public static class Extensions
{
    public static Array GetEnumValues(this Type enumType)
    {
        if (enumType == null) throw new ArgumentException("Type 'enumType' cannot be null");
        if (!enumType.IsEnum) throw new ArgumentException("Type '" + enumType.Name + "' is not an enum");

        Int32 i = 0;
        Boolean bDefined = true;
        List<String> list = new List<String>();

        do
        {
            if (Enum.IsDefined(enumType, i))
            {                    
                list.Add(Enum.GetName(enumType, i));
                ++i;
            }
            else
            {
                bDefined = false;
            }
        }
        while (bDefined);

        return list.ToArray();
    }
}

Ответ 1

Если бы мне пришлось угадать (непроверенный):

    public static Array GetValues(Type type)
    {
        var fields = type.GetFields(BindingFlags.Static | BindingFlags.Public);
        Array result = Array.CreateInstance(type, fields.Length);
        for(int i = 0 ; i < fields.Length ; i++)
        {
            result.SetValue(Enum.ToObject(type, fields[i].GetValue(null)), i);
        }
        return result;
    }

Обратите внимание, что я не пытаюсь адресовать заказ здесь; порядок полей явно не определен. Поэтому используйте это, чтобы получить значения в определенном порядке.

Ответ 2

Есть еще один вопрос, подобный этому в Итерации через перечисление в Silverlight?, но ни один из ответов там не обеспечивает реализацию, которая точно повторяет способ GetEnumValues()GetEnumNames()). Я использовал один из ответов на этот вопрос, чтобы создать решение, которое должно дать вам то, что вам нужно; Я считаю, что это точно дублирует .NET-функции этих функций в Silverlight, и я загрузил весь тестовый проект для Silverlight, который я использовал для создания функций и тестирования использования: GetEnumValuesSilverlightImpl-StackOverflow-7062208.zip.

Само приложение представляет собой единую форму с одной кнопкой и текстовой областью. Нажатие кнопки выполняет итерацию через каждое из трех значений четырех разных перечислений и записывает эти значения в форму. Это должно быть достаточно просто, чтобы добавить дополнительные тестовые примеры, хотя имейте в виду, что текстовая область не переносит слова, так что это необходимо для учета, если вы хотите, чтобы значения были более широкими, чем текстовая область. Я протестировал исходный тестовый сценарий плаката, выписав все три значения для двух исходных перечислений, выписав все три значения для созданного enum, которые имели три непересекающихся значения, и выписав все три значения для созданного [Flag] enum я который имел три разных значения флага.

Соответствующий код:

EnumValuesExtensions.cs: класс расширений, содержащий вызовы функций

using System;
using System.Linq;
using System.Reflection;

namespace SilverlightApplication1
{
    public static class EnumValuesExtensions
    {
        public static Array GetEnumValues(this Type EnumType)
        {
            if (!EnumType.IsEnum)
                throw new ArgumentException("GetEnumValues: Type '" + EnumType.Name + "' is not an enum");

            return
                (
                  from field in EnumType.GetFields(BindingFlags.Public | BindingFlags.Static)
                  where field.IsLiteral
                  select (object)field.GetValue(null)
                )
                .ToArray();
        }

        public static string[] GetEnumNames(this Type EnumType)
        {
            if (!EnumType.IsEnum)
                throw new ArgumentException("GetEnumNames: Type '" + EnumType.Name + "' is not an enum");

            return
                (
                  from field in EnumType.GetFields(BindingFlags.Public | BindingFlags.Static)
                  where field.IsLiteral
                  select field.Name
                )
                .ToArray();
        }
    }
}

MainPage.xaml.cs: источник формы, содержащий тестовый код

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

using System.Reflection;

namespace SilverlightApplication1
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
        }

        [Flags]
        enum Insects { Creepy = 0x0001, Creepier = 0x0002, Creepiest = 0x0004 };

        enum Cats { Fluffy, Furry, Bald };
        enum Dogs { Big, Fat, Ugly };
        enum Rodents { Cute = 3, Cuter = 7, Cutest = 32 };

        static Type CurrentEnum = typeof(Cats);

        private void btnRunTests_Click(object sender, RoutedEventArgs e)
        {
            // from original test code
            Int32 i = (Int32)Enum.Parse(CurrentEnum, "Bald", true);

            i = i == CurrentEnum.GetEnumValues().Length - 1 ? 0 : i + 1;
            String nextValue = CurrentEnum.GetEnumValues().GetValue(i).ToString();

            textBlock1.Text += nextValue + Environment.NewLine;

            // new test code
            LogEnum(typeof(Cats));
            LogEnum(typeof(Dogs));
            LogEnum(typeof(Rodents));
            LogEnum(typeof(Insects));
        }

        public void LogEnum(Type T)
        {
            Array CurrentEnumValues;
            CurrentEnumValues = T.GetEnumValues();

            for (int i=0; i < CurrentEnumValues.Length; ++i)
            {
                string EnumName = CurrentEnumValues.GetValue(i).ToString();
                int EnumValue = (int)CurrentEnumValues.GetValue(i);
                textBlock1.Text += "[" + EnumName + " = " + EnumValue.ToString() + "], ";
            }

            textBlock1.Text += Environment.NewLine;
        }
    }
}

MainPage.xaml: XAML для тестовой формы

<UserControl x:Class="SilverlightApplication1.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="430" d:DesignWidth="400">

    <Grid x:Name="LayoutRoot" Background="White">
        <TextBlock Height="377" HorizontalAlignment="Left" Margin="12,41,0,0" Name="textBlock1" Text="" VerticalAlignment="Top" Width="376" />
        <Button Content="Run Tests" Height="23" HorizontalAlignment="Left" Margin="12,12,0,0" Name="btnRunTests" VerticalAlignment="Top" Width="75" Click="btnRunTests_Click" />
    </Grid>
</UserControl>

Эти тесты выполняются в Silverlight 3, а расширение GetEnumValues ​​(), похоже, работает идентично с функцией .NET GetEnumValues ​​(), поскольку оно дает имена перечислений при вызове .ToString() и правильных целочисленных значениях, когда (int).

Я не тестировал расширение GetEnumNames(), но он довольно четко работает по аналогии с расширением GetEnumValues ​​(), но если есть какие-то проблемы, я с удовольствием посмотрю.

Благодаря ptoinson и Shimmy для их ответ на аналогичный вопрос, который послужил основой для функций, которые я написал, чтобы ответить на этот вопрос.

Ответ 3

На этом есть две темы, и я не мог заставить ничего работать. После того, как я наткнулся на день, я, наконец, закончил с этим:

    public static Array GetEnumValues(this Type enumType)
    {
        List<int> enumerations = new List<int>();
        FieldInfo[] fields = enumType.GetFields(BindingFlags.Static | BindingFlags.Public);
        object enumObj = enumType.GetType();

        foreach (FieldInfo fieldInfo in fields)
        {
            enumerations.Add((int)fieldInfo.GetValue(enumObj));
        }
        return enumerations.ToArray();
    }