標籤:style blog http color 使用 strong
廢話
從.net3.5發布後,就很多前輩利用泛型創造出了很多很有趣的代碼,通用的轉換方法也被寫的爛了,小弟不才,今天又來寫一遍,只是為了做個人知識的管理和追趕大牛的步伐,請各位路過的大大多多批評指正。
思路
1、基本類型都實現了IConvertible這個介面
2、基本類型都實現了TryParse方法
實現
public static class Converter { /// <summary> /// 轉換為其他繼承IConvertible的類型 /// </summary> /// <typeparam name="T">轉換的類型</typeparam> /// <param name="value">要轉換的值</param> /// <param name="success">是否成功</param> /// <returns></returns> public static T To<T>(this IConvertible value, out bool success) where T : IConvertible { if (value == null) { success = true; return default(T); } Type tResult = typeof(T); if (tResult == typeof(string)) { success = true; return (T)(object)value.ToString(); } MethodInfo mTryParse = tResult.GetMethod("TryParse", BindingFlags.Public | BindingFlags.Static, Type.DefaultBinder, new Type[] { typeof(string), tResult.MakeByRefType() }, new ParameterModifier[] { new ParameterModifier(2) }); var parameters = new object[]{value.ToString(), default(T)}; success = (bool)mTryParse.Invoke(null, parameters); return success ? (T)parameters[1] : default(T); } /// <summary> /// 轉換為其他繼承IConvertible的類型 /// </summary> /// <typeparam name="T">轉換的類型</typeparam> /// <param name="value">要轉換的值</param> /// <returns></returns> public static T To<T>(this IConvertible value) where T : IConvertible { bool success; return To<T>(value, out success); } }
單元測試
[TestClass] public class UnitTessConverter { [TestMethod] public void TestTo() { int i = 1; double dResult = i.To<double>(); Assert.AreEqual(i, 1d); Assert.AreEqual(‘1‘, i.To<char>()); double d = 1.1d; int iResult = d.To<int>(); Assert.AreEqual(0, iResult); float fResult = d.To<float>(); Assert.AreEqual(1.1f, fResult); d = 1d; Assert.AreEqual(1, d.To<int>()); float f = 1.1f; iResult = f.To<int>(); Assert.AreEqual(0, iResult); string str = "1.1"; Assert.AreEqual(1.1f, str.To<float>()); Assert.AreEqual(1.1d, str.To<double>()); Assert.AreEqual((decimal)1.1, str.To<decimal>()); str = "1990-10-1 12:00"; Assert.AreEqual(new DateTime(1990, 10, 1, 12, 0, 0), str.To<DateTime>()); str = "100dd"; bool success; Assert.AreEqual(DateTime.MinValue, str.To<DateTime>(out success)); Assert.IsFalse(success); Assert.AreEqual(0, str.To<int>(out success)); Assert.IsFalse(success); Assert.AreEqual(0, str.To<double>(out success)); Assert.IsFalse(success); Assert.AreEqual(‘\0‘, str.To<char>(out success)); Assert.IsFalse(success); str = null; fResult = str.To<float>(); Assert.AreEqual(0f, fResult); Assert.AreEqual("Hibernating", MachineState.Hibernating.To<string>()); Assert.AreEqual(0, MachineState.PowerOff.To<int>()); } enum MachineState { PowerOff = 0, Running = 5, Sleeping = 10, Hibernating = Sleeping + 5 } }
測試通過
運行效率測試
電腦配置:
效率測試代碼:
class Program { static void Main(string[] args) { System.Diagnostics.Stopwatch st = new System.Diagnostics.Stopwatch(); st.Start(); for (int i = 0; i < 1000000; i++) { i.To<string>().To<double>().To<float>(); } st.Stop(); Console.WriteLine(st.ElapsedMilliseconds); Console.Read(); } }
第一次:19639
第二次:19414
第三次:19262
最佳化
在上面的To方法中,用上了反射,反射是效能殺手,要盡量避免使用,所以我想到了把反射得到的“TryParse”的MethodInfo對象儲存起來。
最佳化後的代碼:
public static class Converter { /// <summary> /// 轉換為其他繼承IConvertible的類型 /// </summary> /// <typeparam name="T">轉換的類型</typeparam> /// <param name="value">要轉換的值</param> /// <param name="success">是否成功</param> /// <returns></returns> public static T To<T>(this IConvertible value, out bool success) where T : IConvertible { if (value == null) { success = true; return default(T); } Type tResult = typeof(T); if (tResult == typeof(string)) { success = true; return (T)(object)value.ToString(); } MethodInfo mTryParse; if (_TryParse.ContainsKey(tResult.FullName)) { mTryParse = _TryParse[tResult.FullName]; } else { mTryParse = tResult.GetMethod("TryParse", BindingFlags.Public | BindingFlags.Static, Type.DefaultBinder, new Type[] { typeof(string), tResult.MakeByRefType() }, new ParameterModifier[] { new ParameterModifier(2) }); _TryParse.Add(tResult.FullName, mTryParse); } var parameters = new object[]{value.ToString(), default(T)}; success = (bool)mTryParse.Invoke(null, parameters); return success ? (T)parameters[1] : default(T); } /// <summary> /// 轉換為其他繼承IConvertible的類型 /// </summary> /// <typeparam name="T">轉換的類型</typeparam> /// <param name="value">要轉換的值</param> /// <returns></returns> public static T To<T>(this IConvertible value) where T : IConvertible { bool success; return To<T>(value, out success); } private static Dictionary<string, MethodInfo> _TryParse = new Dictionary<string, MethodInfo>(); }
重新運行單元測試,得到結果是通過
重新運行“效率測試代碼”
第一次:11836
第二次:12170
第三次:11866
至此結束了這篇文章,望各位大大多多指點。