使用C#2.0中的泛型将定界字符串转换为数组枚举

问题描述 投票:0回答:3

我需要将逗号分隔的字符串转换为通用类中的枚举类型的数组。

问题是我需要基于通用T创建一个数组。

这是我的代码:

class Program
{
    static void Main(string[] args)
    {
        var testIt = new TestIt<TestValues[]>();
        TestValues[] converted = testIt.Convert("Pizza,Sub");
    }
}

public class TestIt<T> 
{
    public T Convert(string delimitedValues)
    {
        var valueType = typeof(T);
        var elementType = valueType;
        if (!valueType.IsArray)
        {
            throw new Exception("T is not an array");
        }

        if (valueType.HasElementType)
        {
            elementType = valueType.GetElementType();
        }

        var elements = delimitedValues.Split(',');
        foreach (var elementValue in elements)
        {
            var newElement = Enum.Parse(elementType, elementValue.Trim(), true);
            // not sure what I can do with the element here
        }

    }
}

public enum TestValues
{
    Unknown,
    Pizza,
    Sub,
    Burger
}

关于如何执行此操作的任何想法?我很困惑!

我尝试创建枚举类型的对象数组,但似乎无法将其转换为T。

请记住,这是。Net Framwork 2.0,所以我的工具箱受到限制。

感谢任何人都可以提供的任何想法。

c# arrays generics enums .net-2.0
3个回答
1
投票

只需对代码进行最少的更改:您就可以使用Array.CreateInstance,因为您已经知道数组长度(在elements.Length之后是Split()),然后调用Convert.ChangeType()以将Array转换为T

public T Convert(string delimitedValues)
{
    var valueType = typeof(T);
    var elementType = valueType;
    if (!valueType.IsArray)
    {
        throw new Exception("T is not an array");
    }

    if (valueType.HasElementType)
    {
        elementType = valueType.GetElementType();
    }

    var elements = delimitedValues.Split(',');

    var arrayToReturn = Array.CreateInstance(elementType, elements.Length);

    for (int i = 0; i < elements.Length; i++ )
    {
        var newElement = Enum.Parse(elementType, elements[i].Trim(), true);
        arrayToReturn.SetValue(newElement, i);
    }

    return (T)System.Convert.ChangeType(arrayToReturn, valueType);
}

7
投票

尝试这个课程:

public class TestIt
{
    public static T[] Convert<T>(string delimitedValues)
    {
        if (!typeof(T).IsEnum)
        {
            throw new ArgumentException();
        }

        if (delimitedValues == string.Empty)
        {
            return new T[0];
        }

        string[] parts = delimitedValues.Split(',');
        T[] converted = Array.ConvertAll(parts, x => (T)Enum.Parse(typeof(T), x));
        return converted;
    }
}

按照惯例,您将T用作通用参数,而不是T[]

使用方式:

TestValues[] values = TestIt.Convert<TestValues>("Unknown,Pizza");

即使减少一班,您也可以做到:

public static T[] Convert<T>(string delimitedValues) where T : struct
{
    if (!typeof(T).IsEnum)
    {
        throw new ArgumentException();
    }

    if (delimitedValues == string.Empty)
    {
        return new T[0];
    }

    string[] parts = delimitedValues.Split(',');
    T[] converted = new T[parts.Length];

    for (int i = 0; i < parts.Length; i++)
    {
        if (!Enum.TryParse(parts[i], out converted[i]))
        {
            throw new FormatException(parts[i]);
        }
    }

    return converted;
}

如果需要,您甚至可以使用一个将返回T?[]的版本(因此是可为空的枚举的数组)

public static T?[] ConvertNullable<T>(string delimitedValues) where T : struct
{
    if (!typeof(T).IsEnum)
    {
        throw new ArgumentException();
    }

    if (delimitedValues == string.Empty)
    {
        return new T[0];
    }

    string[] parts = delimitedValues.Split(',');
    T?[] converted = new T?[parts.Length];

    for (int i = 0; i < parts.Length; i++)
    {
        if (parts[i] == string.Empty)
        {
            continue;
        }

        T value;

        if (!Enum.TryParse(parts[i], out value))
        {
            throw new FormatException(parts[i]);
        }

        converted[i] = value;
    }

    return converted;
}

使用类似;

TestValues?[] values = TestIt.ConvertNullable<TestValues>(",Unknown,,Pizza,");

请注意,最后一个版本不会跳过“无效”的值,而是会继续抛出它们。只需将string.Empty元素转换为null。令人遗憾的是,这里存在一个问题:如果您输入ConvertNullable<TestValues>(string.Empty),它将返回一个TestValues[0],但是该字符串甚至可以转换为TestValues[1] { null }

现在,如果您真的想要一份比萨饼,包括所有内容:

public static class EnumSplitter
{
    public static T[] Convert<T>(string delimitedValues) where T : struct
    {
        if (!typeof(T).IsEnum)
        {
            throw new ArgumentException();
        }

        if (delimitedValues == string.Empty)
        {
            return new T[0];
        }

        string[] parts = delimitedValues.Split(',');
        T[] converted = new T[parts.Length];

        for (int i = 0; i < parts.Length; i++)
        {
            if (!Enum.TryParse(parts[i], out converted[i]))
            {
                throw new FormatException(parts[i]);
            }
        }

        return converted;
    }

    public static TArray ConvertArray<TArray>(string delimitedValues) where TArray : IList
    {
        return MethodCache<TArray>.Convert(delimitedValues);
    }

    public static T?[] ConvertNullable<T>(string delimitedValues) where T : struct
    {
        if (!typeof(T).IsEnum)
        {
            throw new ArgumentException();
        }

        if (delimitedValues == string.Empty)
        {
            return new T?[0];
        }

        string[] parts = delimitedValues.Split(',');
        T?[] converted = new T?[parts.Length];

        for (int i = 0; i < parts.Length; i++)
        {
            if (parts[i] == string.Empty)
            {
                continue;
            }

            T value;

            if (!Enum.TryParse(parts[i], out value))
            {
                throw new FormatException(parts[i]);
            }

            converted[i] = value;
        }

        return converted;
    }

    public static TArray ConvertNullableArray<TArray>(string delimitedValues) where TArray : IList
    {
        return MethodCache<TArray>.Convert(delimitedValues);
    }

    private static class MethodCache<TArray> where TArray : IList
    {
        public static readonly Func<string, TArray> Convert;

        static MethodCache()
        {
            if (!typeof(TArray).IsArray)
            {
                throw new ArgumentException("TArray");
            }

            Type element = typeof(TArray).GetElementType();
            Type element2 = Nullable.GetUnderlyingType(element);

            if (element2 == null)
            {
                Convert = (Func<string, TArray>)Delegate.CreateDelegate(typeof(Func<string, TArray>), typeof(EnumSplitter).GetMethod("Convert").MakeGenericMethod(element));
            }
            else
            {
                Convert = (Func<string, TArray>)Delegate.CreateDelegate(typeof(Func<string, TArray>), typeof(EnumSplitter).GetMethod("ConvertNullable").MakeGenericMethod(element2));
            }
        }
    }
}

我使用MethodCache<>类将反射调用缓存到“正确的” Convert<>方法。

用途:

TestValues[] arr1 = EnumSplitter.Convert<TestValues>("Unknown,Pizza");
TestValues?[] arr2 = EnumSplitter.ConvertNullable<TestValues>("Unknown,,Pizza,");
TestValues[] arr3 = EnumSplitter.ConvertArray<TestValues[]>("Unknown,Pizza");
TestValues?[] arr4 = EnumSplitter.ConvertNullableArray<TestValues?[]>("Unknown,,Pizza,");

0
投票
public static T[] ToEnumsArray<T>(this string stringValuesWithDelimeter) where T : struct
    {
        var result = new List<T>();
        if (!string.IsNullOrWhiteSpace(stringValuesWithDelimeter))
        {
            var arr = stringValuesWithDelimeter.Split(',');
            foreach (var item in arr)
            {
                if (Enum.TryParse(item, true, out T enumResult))
                {
                    result.Add(enumResult);
                }
            }
        }
        return result.ToArray();
    }
© www.soinside.com 2019 - 2024. All rights reserved.