在C#中将字符串转换为泛型类型(基本或数组)

Mik*_*ail 3 c# generics type-conversion

我想将字符串转换为给定的泛型类型T.它可以是基本类型或字符串(例如intstring),或基本类型或字符串的数组(例如int[]string[]).我有以下功能:

T Str2Val<T>(string str)
{
  return (T)Convert.ChangeType(str, typeof(T));
}
Run Code Online (Sandbox Code Playgroud)

它适用于基本类型.但它不能T成为一个数组E[]并且str是一个以逗号分隔的值列表.

我可以很容易地检查是否T是一个数组typeof(T).IsArray.然后我有两个解决方案:使用标量在同一函数中解析数组,如下所示:

  if (!typeof(T).IsArray)
  {
    return (T)Convert.ChangeType(str, typeof(T));
  }
  else
  {
    // Handle an array
  }
Run Code Online (Sandbox Code Playgroud)

或者实现两个重载函数:一个用于泛型T,第二个用于泛型E[].但是,两种解决方案都失败了.我不能在else子句中使用任何特定于数组的代码,因为它必须与标量兼容.当C#实际上是一个数组E[]时,C#无法选择适当的重载T.

我该怎么办?

Chr*_*air 7

我会创建一些您注册的自定义解析器列表,然后稍后使用,因为您似乎想要使用自定义规则:

public static class StringParsers
{
    private static Dictionary<Type, object> Parsers = new Dictionary<Type, object>();

    public static void RegisterParser<T>(Func<string, T> parseFunction)
    {
        Parsers[typeof(T)] = parseFunction;
    }

    public static T Parse<T>(string input)
    {
        object untypedParser;
        if (!Parsers.TryGetValue(typeof(T), out untypedParser))
            throw new Exception("Could not find a parser for type " + typeof(T).FullName);

        Func<string, T> parser = (Func<string, T>)untypedParser;

        return parser(input);
    }
}
Run Code Online (Sandbox Code Playgroud)

在应用程序初始化期间,您将在应用程序中注册稍后要使用的类型(我猜这是已知的,因为您使用的是泛型):

StringParsers.RegisterParser<string[]>(input => input.Split(','));
StringParsers.RegisterParser<int[]>(input => input.Split(',').Select(i => Int32.Parse(i)).ToArray());
StringParsers.RegisterParser<int>(input => Int32.Parse(input));
Run Code Online (Sandbox Code Playgroud)

最后,你可以简单地称它:

string testArrayInput = "1,2,8";

int[] integers = StringParsers.Parse<int[]>(testArrayInput); // {1, 2, 8}

string[] strings = StringParsers.Parse<string[]>(testArrayInput); // {"1", "2", "8"}

int singleInt = StringParsers.Parse<int>("9999"); //9999
Run Code Online (Sandbox Code Playgroud)

现在,这是一个非常简单的实现.您可能希望扩展它,而不是使用类型,Func<string, T>它可能使用IStringParser接口,如果需要,您可以提供更深入的解析实现.此外,您可能希望使其线程安全(除非您确定不会出现问题,或者您确定在启动时注册是任何使用之前)

编辑:如果你真的,真的,真的想在一个函数中考虑你的逗号分隔数组,那么你可以使用这个:

public static T Str2Val<T>(string str)
{
    if (!typeof(T).IsArray)
        return (T)Convert.ChangeType(str, typeof(T));

    Type elementType = typeof(T).GetElementType();

    string[] entries = str.Split(',');
    int numberOfEntries = entries.Length;

    System.Array array = Array.CreateInstance(elementType, numberOfEntries);

    for(int i = 0; i < numberOfEntries; i++)
        array.SetValue(Convert.ChangeType(entries[i], elementType), i);

    return (T)(object)array;
}
Run Code Online (Sandbox Code Playgroud)

但这感觉很错误.必须有一个更好的方法,并避免亚历山大的答案中的双重通用输入,但你去.