通过反射填充Enum数组

时间:2012-09-07 11:42:29

标签: c# reflection propertyinfo

我有一个读取一些XML并填充对象的方法。这是通过基于XML对象的属性名称中的元素名称的反射来完成的。这适用于基本对象类型,但我正在努力使用枚举数组。

所以我有一个PropertyInfo对象(让我们调用它属性)为我的枚举数组属性,我有一个字符串值(让我们称之为值)包含表示枚举值的逗号分隔数字(例如“1,3,5”)

我试过了:

property.SetValue(this, value.Split(',').Select(i => int.Parse(i)).ToArray(), null);

property.SetValue(this, value.Split(',').Select(i => Enum.ToObject(property.PropertyType.GetElementType(), int.Parse(i))).ToArray(), null);

但没有快乐。在第一个代码示例中,Select.ToArray的结果是一个int [],然后抛出一个解析错误。类似于第二种情况,但Select.ToArray返回一个对象[]并再次抛出一个解析错误。

我想写这个就像枚举类型未知一样。

有什么想法吗?

3 个答案:

答案 0 :(得分:2)

试试这个:

// create the enum values as object[]
var values = value.Split(',')
  .Select(i => Enum.Parse(property.PropertyType.GetElementType(), i))
  .ToArray()

// create array of correct type
Array array = (Array)Activator.CreateInstance(property.PropertyType, values.Length);

// copy the object values to the array
int i = 0;
foreach(var value in values)
{
  array.SetValue(value, i++);
}

// set the property
property.SetValue(this, array, null)

可能有一种更简单的方法,但关键是你要创建一个正确类型的数组。

答案 1 :(得分:1)

以下是'正确'的方法。通过反射处理数组有点难看:

// assume that property is an array of some enum 

var enumType = property.PropertyType.GetElementType();
var values = value.Split(',');
var enumArray = Array.CreateInstance(enumType, values.Length);
for (int i = 0; i < enumArray.Length; ++i)
    enumArray.SetValue(Enum.Parse(enumType, values[i]), i);

property.SetValue(x, enumArray);

重点是您需要使用正确的元素类型创建数组。如果您只使用ToArray,那么最多只会得到int[],最差的是object[]

可以实际将int[]数组设置为枚举数组属性(只要枚举有int作为其基础类型)。这只是对您的第一个示例的轻微更改,您不需要提供第三个参数:

property.SetValue(x, value.Split(',').Select(i => int.Parse(i)).ToArray());

但是,设置为此属性的数组将具有“错误”类型。我不确定这是否会导致任何问题,但如果您正在进行大量依赖于运行时类型的反射,则可能会遇到一些问题。 (如果要解析命名的枚举值,这也不起作用。)

答案 2 :(得分:0)

使用通用方法执行此操作的另一种方法:

public class Class2
{
    public enum TestEnum
    {
        One = 1,
        Two = 2,
        Three = 3
    }

    public TestEnum[] TestValues { get; set; }

    public static T[] ConvertToEnum<T>(IEnumerable<int> values)
    {
        return values
            .Select(v => (T)Enum.ToObject(typeof(T), v))
            .ToArray();
    }

    public void Test()
    {
        var property = this.GetType().GetProperty("TestValues");

        var value = "1,2,3";

        var convert = this.GetType()
            .GetMethod("ConvertToEnum")
            .MakeGenericMethod(property.PropertyType.GetElementType());

        var intValues = value.Split(',').Select(v => int.Parse(v));

        var result = convert.Invoke(null, new[] { intValues });

        property.SetValue(this, result, null);
    }
}

重点是使数组创建更具可读性。额外奖励:ConvertToEnum<T>方法可以在其他地方重复使用。