簡體   English   中英

在C#中將字符串轉換為泛型類型(基本或數組)

[英]Convert string to generic type (basic or array) in C#

我想將字符串轉換為給定的泛型類型T 它可以是基本類型或字符串(例如intstring ),也可以是基本類型或字符串的數組(例如int[]string[] )。 我有以下功能:

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

它適用於基本類型。 但它失敗,因為T是一個數組E[]str是一個以逗號分隔的值列表。

我可以很容易地檢查T是否是typeof(T).IsArray的數組。 然后我有兩個解決方案:使用標量在同一函數中解析數組,如下所示:

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

或者實現兩個重載函數:一個用於泛型T ,第二個用於泛型E[] 但是,兩種解決方案都失敗了。 我不能在else子句中使用任何特定於數組的代碼,因為它必須與標量兼容。 T實際上是一個數組時,C#無法用E[]選擇適當的過載。

我該怎么辦?

我會創建一些您注冊的自定義解析器列表,然后稍后使用,因為您似乎想要使用自定義規則:

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

在應用程序初始化期間,您將在應用程序中注冊稍后要使用的類型(我猜這是已知的,因為您使用的是泛型):

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

最后,你可以簡單地稱它:

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接口,如果需要,您可以提供更深層次的解析實現。 此外,您可能希望使其線程安全(除非您確定不會出現問題,或者您確定在啟動時注冊是任何使用之前

編輯:如果你真的,真的, 真的想在一個函數中考慮你的逗號分隔數組,那么你可以使用這個:

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

但這感覺很錯誤 必須有一個更好的方法,並避免亞歷山大的答案中的雙重通用輸入,但你去。

顯式元素類型傳遞的另一種解決方案

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

static E[] Str2Val<T, E>(string str)
    where T : ICollection<E>
{
    return str.Split(',').Select(x => (E)Convert.ChangeType(x, typeof(E))).ToArray();
}

運用

Str2Val<int>("1")
Str2Val<int[], int>("1,3")

也許這樣的事情會有所幫助:

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

    var elementType = typeof(T).GetElementType();
    return str.Split(',').Select(x => Convert.ChangeType(x, elementType)).ToArray();
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM