在C#中将字符串转换为通用类型(基本或数组) [英] Convert string to generic type (basic or array) in C#

查看:113
本文介绍了在C#中将字符串转换为通用类型(基本或数组)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I want to convert a string to a given generic type T. It may be either basic type or string (e.g. int or string), or an array of a basic types or strings (e.g. int[] or string[]). I have the following function:

T Str2Val<T>(string str)
{
  return (T)Convert.ChangeType(str, typeof(T));
}

它对于基本类型非常有效.但是T是数组E[],而str是逗号分隔的值列表,则失败.

It works well for basic types. But it fails for T being an array E[] and str being a comma-separated list of values.

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

I can easily check whether T is an array with typeof(T).IsArray. Then I have two solutions: parse an array in the same function with a scalar, like the following:

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

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

or implement two overloaded functions: one for generic T and second for generic E[]. However, both of solutions fail. I cannot use any array-specific code in the else-clause since it must be compatible with a scalar. And C# cannot pick proper overload with E[] when T is actually an array.

我该怎么办?

推荐答案

我将创建一些注册的自定义解析器列表,然后注册这些自定义解析器,然后再利用它们,因为您似乎仍然想使用自定义规则:

I would create some listing of custom parsers that you register then later leverage since you seem to be wanting to use custom rules anyway:

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);
    }
}

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

During your application initialization, you would register the types you intend to use later in your application (I'm guessing this is known since you're using generics):

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));

最后,您可以简单地称呼它:

Finally, you can call it simply:

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

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

Now, this is a pretty simple implementation. You may wish to extend it so instead of using type Func<string, T> it might use an IStringParser interface and you can provide deeper implementations of the parsing if necessary. Furthermore, you may wish to make it thread safe (unless you're sure that won't be an issue, or if you are sure your registration on startup is before any usages)

如果您真的真的真的希望它们全部包含在一个函数中,并且只用逗号分隔数组,那么您可以使用此函数:

If you really, really, really want it all in one function just accounting for your comma delimited array, then you can use this:

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;
}

但这感觉很不对劲.必须有更好的方法,避免在Alexander的答案中输入双重通用输入,但是您就可以了.

But this feels so wrong. There must be a better way and to avoid the double generic input in Alexander's answer, but there you go.

这篇关于在C#中将字符串转换为通用类型(基本或数组)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆