Как создать метод расширения 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();
}