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