现在的位置: 首页 > 综合 > 正文

使用C#,不使用任何Parse,TryParse,Convert方法,将数字字符串转换成整数

2013年10月13日 ⁄ 综合 ⁄ 共 2260字 ⁄ 字号 评论关闭

听朋友说,遇到这样的一个面试题,然后来问我,想了半天,居然没有找到好办法,又去问了问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的方式好,也算是一种解决方案吧。

 

抱歉!评论已关闭.