Fork me on GitHub

由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则用在需要被调用的方法修改调用者的引用的时候,可以不断改变引用地址对应的值。

我小小菜鸟一个,不到之处,敬请拍砖!

posted @ 2013-03-16 21:15  种花生的读书人  阅读(486)  评论(3编辑  收藏  举报

该博客仅作为记录笔记,转载随意