如何將字符串動態轉換為指定的值類型
先看一個字符串動態轉換的典型例子
如下函數,我們只知道value 是一個基本值類型,比如(System.Int32, System.Int16, System.Double 等等) 或者是一個字符串類型。但我們無法在編碼時確定這個value 具體是什么類型,它可能是由一個外部組件從某個數據源中讀出來的基本類型中的一種類型的實例或者是字符串類型實例。
這個函數希望實現比較value 是否在minValue, maxValue這兩個字符串對應的數值區間類,其中minValue 和 maxValue 構成一個閉區間,即
value in [minValue, maxValue] |
要解決這個問題,我們需要解決兩個基本問題。
1. 如何比較value 和 minValue, maxValue
2. 如何將minValue 和 maxValue 轉換到value 對應的數據類型
首先我們來看如何進行比較
所有的基本值類型和string 類型都實現 IComparable這個接口。我們可以指定 value 為 IComparable,然后調用CompareTo來進行比較。不過這里有個問題,CompareTo 函數的參數obj 雖然是一個 object 類型,但這個 obj 的類型必須和 value 一致,否則將發生異常。也就是說我們不能把minValue 任意轉換成某個類型比如 long 帶進去,而需要將 minValue 和 maxValue 轉換成和 value 一樣的類型才行。
下面我們就來討論如何將字符串動態轉換為指定的值類型
我們需要實現下面的函數:
public static object ToType(Type type, string value) |
type 為指定的類型,value 為輸入的字符串。
首先我們知道所有的基本值類型都有一個叫 Parse 靜態函數,我們只要把這個靜態函數反射出來,就可以通過這個靜態函數將字符串動態轉換成對應的值類型。
下面代碼給出如何反射出這個靜態函數。通過向對象type(Type類型)的GetMethods 函數輸入 BindingFlags.Static
| BindingFlags.Public 參數,我們可以枚舉出這個類型所有的靜態公共函數。
然后我們判斷這個函數的名稱是否為 "Parse" ,由于 Parse 函數有多個重載,但一個參數的重載只有 Parse (String)
所以我們需要判斷mi 只有一個參數,這時取到的 mi 就是 Parse (String) 函數。
MethodInfo parseMethod = null; |
接下來就是如何調用這個函數來動態轉換字符串了。
如下面代碼,我們調用MethodInfo 的 Invoke 方法來動態調用這個函數,由于是靜態函數,第一個參數 obj 傳入null. 并在第二個參數中帶入value 這個參數。
parseMethod.Invoke(null, new object[] { value }); |
下面給出字符串動態轉換為指定類型的完整代碼
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;namespace Eagelt.Convert
{
public class ConvertString
{
public static object ToType(Type type, string value)
{
if (type == typeof(string))
{
return value;
}MethodInfo parseMethod = null;
foreach (MethodInfo mi in type.GetMethods(BindingFlags.Static
| BindingFlags.Public))
{
if (mi.Name == "Parse" && mi.GetParameters().Length == 1)
{
parseMethod = mi;
break;
}
}if (parseMethod == null)
{
throw new ArgumentException(string.Format(
"Type: {0} has not Parse static method!", type));
}return parseMethod.Invoke(null, new object[] { value });
}
}
}
MyComparer 函數的完整代碼
public static bool MyComparer(object value, string minValue, string maxValue)
{
IComparable comparableObj = value as IComparable;object min;
object max;if (comparableObj == null)
{
throw new ArgumentException(string.Format(
"Type: {0} does not inherit from IComparable", value.GetType()));
}min = ConvertString.ToType(value.GetType(), minValue);
max = ConvertString.ToType(value.GetType(), maxValue);return comparableObj.CompareTo(min) >= 0 && comparableObj.CompareTo(max) <= 0;
}
測試代碼
Console.WriteLine(MyComparer(2, "1", "3"));
Console.WriteLine(MyComparer(3, "1", "2"));
Console.WriteLine(MyComparer((byte)2, "1", "3"));
Console.WriteLine(MyComparer((double)3, "1", "2"));
Console.WriteLine(MyComparer("3", "1", "2"));
測試結果
True |
最后提一個簡單的問題,供大家思考,如果我們需要將字符串動態轉換成我們自己定義的復雜類型,如何實現呢?
比如我們有一個結構
struct UInt128 |
我們將這個結構的實例對象傳入到函數
Console.WriteLine(MyComparer((UInt128)2, "1", "3")); |
這樣可以嗎?怎樣做才能做到呢?
【編輯推薦】