如何將字符串動態(tài)轉(zhuǎn)換為指定的值類型
先看一個字符串動態(tài)轉(zhuǎn)換的典型例子
如下函數(shù),我們只知道value 是一個基本值類型,比如(System.Int32, System.Int16, System.Double 等等) 或者是一個字符串類型。但我們無法在編碼時確定這個value 具體是什么類型,它可能是由一個外部組件從某個數(shù)據(jù)源中讀出來的基本類型中的一種類型的實例或者是字符串類型實例。
這個函數(shù)希望實現(xiàn)比較value 是否在minValue, maxValue這兩個字符串對應(yīng)的數(shù)值區(qū)間類,其中minValue 和 maxValue 構(gòu)成一個閉區(qū)間,即
value in [minValue, maxValue] |
要解決這個問題,我們需要解決兩個基本問題。
1. 如何比較value 和 minValue, maxValue
2. 如何將minValue 和 maxValue 轉(zhuǎn)換到value 對應(yīng)的數(shù)據(jù)類型
首先我們來看如何進行比較
所有的基本值類型和string 類型都實現(xiàn) IComparable這個接口。我們可以指定 value 為 IComparable,然后調(diào)用CompareTo來進行比較。不過這里有個問題,CompareTo 函數(shù)的參數(shù)obj 雖然是一個 object 類型,但這個 obj 的類型必須和 value 一致,否則將發(fā)生異常。也就是說我們不能把minValue 任意轉(zhuǎn)換成某個類型比如 long 帶進去,而需要將 minValue 和 maxValue 轉(zhuǎn)換成和 value 一樣的類型才行。
下面我們就來討論如何將字符串動態(tài)轉(zhuǎn)換為指定的值類型
我們需要實現(xiàn)下面的函數(shù):
public static object ToType(Type type, string value) |
type 為指定的類型,value 為輸入的字符串。
首先我們知道所有的基本值類型都有一個叫 Parse 靜態(tài)函數(shù),我們只要把這個靜態(tài)函數(shù)反射出來,就可以通過這個靜態(tài)函數(shù)將字符串動態(tài)轉(zhuǎn)換成對應(yīng)的值類型。
下面代碼給出如何反射出這個靜態(tài)函數(shù)。通過向?qū)ο髏ype(Type類型)的GetMethods 函數(shù)輸入 BindingFlags.Static
| BindingFlags.Public 參數(shù),我們可以枚舉出這個類型所有的靜態(tài)公共函數(shù)。
然后我們判斷這個函數(shù)的名稱是否為 "Parse" ,由于 Parse 函數(shù)有多個重載,但一個參數(shù)的重載只有 Parse (String)
所以我們需要判斷mi 只有一個參數(shù),這時取到的 mi 就是 Parse (String) 函數(shù)。
MethodInfo parseMethod = null; |
接下來就是如何調(diào)用這個函數(shù)來動態(tài)轉(zhuǎn)換字符串了。
如下面代碼,我們調(diào)用MethodInfo 的 Invoke 方法來動態(tài)調(diào)用這個函數(shù),由于是靜態(tài)函數(shù),第一個參數(shù) obj 傳入null. 并在第二個參數(shù)中帶入value 這個參數(shù)。
parseMethod.Invoke(null, new object[] { value }); |
下面給出字符串動態(tài)轉(zhuǎn)換為指定類型的完整代碼
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 函數(shù)的完整代碼
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"));
測試結(jié)果
True |
最后提一個簡單的問題,供大家思考,如果我們需要將字符串動態(tài)轉(zhuǎn)換成我們自己定義的復(fù)雜類型,如何實現(xiàn)呢?
比如我們有一個結(jié)構(gòu)
struct UInt128 |
我們將這個結(jié)構(gòu)的實例對象傳入到函數(shù)
Console.WriteLine(MyComparer((UInt128)2, "1", "3")); |
這樣可以嗎?怎樣做才能做到呢?
【編輯推薦】