听朋友说,遇到这样的一个面试题,然后来问我,想了半天,居然没有找到好办法,又去问了问PDF.NET开发框架 技术群里面的朋友,群友 laoliu给了一个非常简单的方法,值得推荐:
char[] digits = "12345".ToCharArray(); int result = 0; foreach (char c in digits) { result = (result * 10) + (c - '0'); } Console.Write(result);
后来自己想了想,是否可以试试反射或者表达式树,写了如下的代码:
使用Emit 方式来转换:
public delegate int UseStringToInt(string input); static UseStringToInt BuildStringToInt() { // // 下面的代码将创建类似的方法: // int Fun("123")(return 123;); // DynamicMethod method = new DynamicMethod("MyConvert", typeof(int), new Type[] { typeof(string) }); // 获取动态函数的 IL 生成器 var il = method.GetILGenerator(); // 创建一个本地变量,主要用于 Object Type to Propety Type var local = il.DeclareLocal(typeof(int), true); // 加载第 1 个参数的 value il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Unbox, typeof(int));// 拆箱 string = (string)object; 不同类型的拆箱会出现问题 il.Emit(OpCodes.Stloc, local);// 将上面的拆箱或转换,赋值到本地变量,现在这个本地变量是一个与目标函数相同数据类型的字段了。 il.Emit(OpCodes.Ret); // 返回 return (UseStringToInt)method.CreateDelegate(typeof(UseStringToInt)); }
本来以为使用IL代码的Unbox指令,强行将字符串拆箱出来,很可惜,运行的时候提示“代码不稳定,不能运行。”
再试试委托,但使用前先定义个简单的对象:
public class TestClass { private int _value = 500; public int Value { get { return _value; } set { _value = value; } } }
接着使用下面的委托,听说这种方式是访问对象属性最快的方式,可以考虑在ORM中使用:
//得到指定的属性 System.Reflection.PropertyInfo p = typeof(TestClass).GetProperty("Value", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); //创建get,set委托 TestClass t = new TestClass(); Func<int> PGet = Delegate.CreateDelegate(typeof(Func<int>), t, p.GetGetMethod(true)) as Func<int>; Action<int> PSet = Delegate.CreateDelegate(typeof(Action<int>), t, p.GetSetMethod(true)) as Action<int>; //访问属性 PSet(5); int i = PGet();
可惜,上面的代码中Action不能指定String参数,否则会有运行时错误;
还想到一招,就是使用CodeDom,将字符串形式的代码写进去,然后再动态编译了,代码量太复杂了,这就不讲了。
最后,想到一个“偏方”,可以使用对象的序列化和反序列化:
//不使用Parse,TryParse,Convert等,将字符串 "12345" 转换成一个整数 //使用XML序列化的方式,重新设置转换的值 TestClass t2 = new TestClass(); t2.Value = 100; XmlSerializer xs = new XmlSerializer(typeof(TestClass)); System.IO.MemoryStream ms = new System.IO.MemoryStream(); xs.Serialize(ms, t2); String s = System.Text.Encoding.UTF8.GetString(ms.ToArray()); string newValue = "12345"; string replaceString = "<Value>100</Value>"; s = s.Replace(replaceString, "<Value>" + newValue + "</Value>"); byte[] bs2 = System.Text.Encoding.UTF8.GetBytes(s); MemoryStream ms2 = new MemoryStream(bs2); TestClass t3 = (TestClass)xs.Deserialize(ms2); int result = t3.Value;
实验成功,但显然这种代码没有laoliu的方式好,也算是一种解决方案吧。