How do I create a GetEnumValues extension method in Silverlight that works the same way as in .NET?
Below is a piece of code I find useful in that I can use it to nip round enums quickly. CurrentEnum stores a reference to the enum that was used to provide the strings, in this case "Bald" and it can change.
What I am trying to do is replicate the same functionality in Silverlight which does not have a GetEnumValues function. The preferable solution would be an extension method that can be used in the same way as in my example below.
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:
Here is what I have decided on for now:
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开发者_JAVA技巧) 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();
}
}
If I had to guess (untested):
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;
}
Note that I don't attempt to address the ordering here; the order of fields is explicitly not defined. So use this to get the values in no specific order.
There is another question similar to this one at Iterating through an enumeration in Silverlight? but none of the answers there provides an implementation that exactly replicates the way GetEnumValues()
(and GetEnumNames()
) work. I used one of the answers from that question to create a solution which should give you what you need; I believe this exactly duplicates the .NET functionality of those functions in Silverlight, and I have uploaded the entire test project for Silverlight that I used to create the functions and test the usage: GetEnumValuesSilverlightImpl-StackOverflow-7062208.zip.
The application itself is a single form with a single button and text area. Clicking the button iterates through each of three values of four different enumerations, and logs those values to the form. It should be easy enough to add extra test cases, although be aware that the text area does not word wrap, so that will be needed to be accounted for if one wishes to put values wider than the text area. I tested the original poster's test case, writing out all three values for the two original enums, writing out all three values for an enum I created that had three non contiguous values, and writing out all three values for a [Flag]
enum I created that had three different flag values.
The relevant code:
EnumValuesExtensions.cs
: extensions class containing function calls
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
: Form source containing Test Code
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
: The XAML for the Test Form
<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>
These tests are running in Silverlight 3, and the GetEnumValues() extension does appear to work identically to the .NET GetEnumValues() function, as it gives enum names when .ToString() is called, and the proper integer values when casted to (int).
I have not tested the GetEnumNames() extension, but it fairly clearly works by analogy to the GetEnumValues() extension, but if there are any issues I will be happy to take a look.
Thanks to ptoinson and Shimmy for their answer to a similar question, which formed the basis for the functions I wrote to answer this question.
There are two threads on this and I couldn't get anything to work. After fumbling around for a day I finally ended up with this:
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();
}
精彩评论