由TryParse到out/ref
先看一下这段代码,使用reflector反编译过来的
public static bool TryParse(string s, out int result) { return Number.TryParseInt32(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result); }
可知TryParse()返回的是一个bool类型,这里还使用了个out关键字。
首先解决TryParse()这个问题
(1)TryParse()在进行转换时,先进行尝试转换,如果转换失败,返回0
static void Main(string[] args) { string a = "234dff"; int b; int.TryParse(a, out b); Console.WriteLine(b); Console.ReadLine(); }
如果转换成功,返回int类型的值
int.TryParse(a, out b); 是指将字符串强制转换并且赋值给b,这里必须使用out关键字修饰,至于为什么使用待会再说。
(2)将一个字符串转换成一个相应类型的值时,可以使用Convert() Parse(),那么这三者有什么区别?
static void Main(string[] args) { string a = "234dff"; int b; int.TryParse(a, out b);//不报错,返回一个结果为0 // b = Convert.ToInt32(a);//报错类型输入的字符串不正确 // b = int.Parse(a);//报错类型输入的字符串不正确 Console.WriteLine(b); Console.ReadLine(); }
int.Parse()
public static int Parse(string s) { return Number.ParseInt32(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo); }
Convert.ToInt32() 不安全的类型
[SecuritySafeCritical] public static unsafe int ToInt32(byte[] value, int startIndex) { if (value == null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); } if (((ulong) startIndex) >= value.Length) { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index); } if (startIndex > (value.Length - 4)) { ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall); } fixed (byte* numRef = &(value[startIndex])) { if ((startIndex % 4) == 0) { return *(((int*) numRef)); } if (IsLittleEndian) { return (((numRef[0] | (numRef[1] << 8)) | (numRef[2] << 0x10)) | (numRef[3] << 0x18)); } return ((((numRef[0] << 0x18) | (numRef[1] << 0x10)) | (numRef[2] << 8)) | numRef[3]); } }
如果我们将这三者的转换能力排个序,那么TryParse()>Parse()>Convert()
再说说TryParse(string s, out int b)中的关键字out(说白了就是表明我这个参数是用来传出的)
(1)在方法的参数类型前加out,那么传参数的时候也必须在参数前加out表明这个参数不是传入的,而是用来传出值的。
(2)如果参数是out形式传入的,那么在传入前可以不赋初值。
(3)在方法中对于out修饰的参数,必须在使用前先赋值。
class Program { static void Main(string[] args) { int number=2; Test(out number); Console.WriteLine(number); Console.ReadLine(); } static void Test(out int b) { int c = 100; b =c+1; } }
结果是101
具体用法变化很多
说到这,还有个ref关键字(这个关键字
ref:引用传递,传递的是地址。既能传值,又能赋值(地址)。
)
class Program { static void Main(string[] args) { int number=2; Test(ref number); Console.WriteLine(number); Console.ReadLine(); } static void Test(ref int b) { int c = 100; b =c+1; } }
结果:`101
好像没有什么区别是的。
接着改改看
class Program { static void Main(string[] args) { int b = 10; Test(ref b); Console.ReadLine(); } static void Test(ref int b) { Console.WriteLine(b); } }
结果是10
class Program { static void Main(string[] args) { int b = 10; Test(out b); Console.ReadLine(); } static void Test(out int b) { Console.WriteLine(b); } }
错误 1 使用了未赋值的 out 参数“b”
编译未通过
到这也就说明了问题的本质了:
(1)使用out必须在方法返回之前或再使用out参数前为 out 参数赋值,也就是说out不能接受地址没有值的参数;而ref可以。
(2)out参数传递进来的是值的拷贝,传递出去的是什么就看代码怎么写了;ref传递进来的是值的引用地址,这个地址可以是空的引用。
总之:out适合用在需要retrun多个返回值的地方,而ref则用在需要被调用的方法修改调用者的引用的时候,可以不断改变引用地址对应的值。
我小小菜鸟一个,不到之处,敬请拍砖!