从.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
至此结束了这篇文章,望各位大大多多指点。