第五章 方法

2018-07-05  本文已影响0人  向着远方奔跑

5.3 本地变量

下表对比了实例字段和本地变量

实例字段 本地变量
生存期 从实例被创建时开始,
直到实例不再被访问时结束
从它在块中被声明的那点开始,
在块完成执行时结束
隐式初始化 初始化成该类型的默认值 没有隐式初始化。如果变量在使用之前
没有被复制,编译器就会产生一条错误信息
存储区域 由于实例字段是类的成员,
所以所有字段都存储在里,
无论它们是值类型还是引用类型
值类型:存储在
引用类型:引用存储在栈里,数据存储在堆里
5.3.1 类型推断和var关键字

var关键字并不是特定类型变量的符号
它只是语法上的速记,表示任何可以从初始化语句的右边推断出的类型。
使用显式类型名的代码片段和使用var关键字的代码片段在语义上是等价的。
使用var关键字的重要条件:

与dynamic区别

var类型的变量是程序在编译时,编译器会根据语句右边自动推断出var变量的实际类型,并用实际类型替换该变量的声明,看上去好像是我们在编码的时候用实际类型进行声明的。

dynamic类型被编译后,实际是个object类型,只是编译器会对dynamic类型进行特殊处理,使其在编译期间不进行任何类型检查,而是将类型检查放到了运行期。

5.4 本地常量

本地常量和本地变量一样必须声明在块的内部。
常量有两个重要特征:

常量的核心声明如下所示:


说明
关键字const不是一个修饰符,而是核心声明的一部分。它必须直接放在类型的前面


5.9 参数

5.9.1 形参

形参是本地变量,它声明在方法的参数列表中,而不是方法体中。
下例中声明了两个形参:一个int型,一个float型

public void PrintSum(int x, float y)  -->方法头
{         -->
...       -->   方法体
}         -->
5.9.1 实参

当代码调用一个方法时,形参的值必须在方法的代码开始执行之前被初始化

5.10 值参数

值参数,是指在形式参数表中前面没有Var,后面没有类型说明的这一类参数。只传递数值,在函数中对之所进行的改动,不会造成原始变量值的改变。

它类似于局部变量,仅为过程和函数的执行提供初值而不影响调用时的实际参数的值,在调用函数时值参数所对应的实际参数可以是表达式。

使用值参数,通过将实参的值复制到形参的方式把数据传递给方法。方法被调用时,系统做如下操作:

在把变量用作实参之前,变量必须被赋值(输出参数out除外)。对于引用类型,变量可以被设置为一个实际的引用或null。


说明
值类型是指类型本身包含其值。
值参数是把实参的值复制给形参。两个概念不要搞混


class MyClass
    {
        public int Val = 20; //初始化字段为20
    }

    class Program
    {
        static void MyMethod(MyClass f1, int f2)
        {
            f1.Val = f1.Val + 5;  //参数字段加5
            f2 = f2 + 5;          //另一参数加5
            Console.WriteLine("f1.Val:{0}, f2:{1}", f1.Val, f2);
        }

        static void Main()
        {
            MyClass a1 = new MyClass();
            int a2 = 10;

            MyMethod(a1, a2);
            Console.WriteLine("f1.Val:{0}, f2:{1}", a1.Val, a2);
        }
    }

输出结果:

f1.Val:25, f2:15
f1.Val:25, f2:10

下图为实参和形参在方法执行不同阶段的值


值参数

5.11 引用参数


说明
记住要在方法的声明和调用上都使用ref关键字


class MyClass
{
    public int Val = 20; //初始化字段为20
}
class Program
    {
        static void MyMethod(ref MyClass f1, ref int f2)
        {
            f1.Val = f1.Val + 5;  //参数字段加5
            f2 = f2 + 5;          //另一参数加5
            Console.WriteLine("f1.Val:{0}, f2:{1}", f1.Val, f2);
        }

        static void Main()
        {
            MyClass a1 = new MyClass();
            int a2 = 10;

            MyMethod(ref a1, ref a2);
            Console.WriteLine("f1.Val:{0}, f2:{1}", a1.Val, a2);
        }
    }

输出结果:

f1.Val:25, f2:15
f1.Val:25, f2:15

下图展示了方法执行不同阶段实参和形参的值

引用参数,形参就像实参的别名

5.12 引用类型作为值参数和引用参数

下面代码展示第一种情况—将引用类型对象作为值参数传递:

class MyClass { public int Val = 20; }

    class Program
    {
        static void RefAsParameter(MyClass f1)
        {
            f1.Val = 50;
            Console.WriteLine("After member assignment: {0}", f1.Val);
            f1 = new MyClass();
            Console.WriteLine("After new object creation: {0}", f1.Val);
        }

        static void Main(string[] args)
        {
            MyClass a1 = new MyClass();
            Console.WriteLine("Before method Call: {0}", a1.Val);
            RefAsParameter(a1);
            Console.WriteLine("After method Call: {0}", a1.Val);
            Console.ReadKey();
        }
    }

输出结果:


Before method Call: 20
After member assignment: 50
After new object creation: 20
After method Call: 50

下图展示了程序具体的运行原理:

第二种情况将引用类型对象作为引用参数的情况:

class MyClass { public int Val = 20; }

    class Program
    {
        static void RefAsParameter(ref MyClass f1)
        {
            f1.Val = 50;
            Console.WriteLine("After member assignment: {0}", f1.Val);
            f1 = new MyClass();
            Console.WriteLine("After new object creation: {0}", f1.Val);
        }

        static void Main(string[] args)
        {
            MyClass a1 = new MyClass();
            Console.WriteLine("Before method Call: {0}", a1.Val);
            RefAsParameter(ref a1);
            Console.WriteLine("After method Call: {0}", a1.Val);
            Console.ReadKey();
        }
    }

输出结果:


Before method Call: 20
After member assignment: 50
After new object creation: 20
After method Call: 20

下图展示了程序的运行原理:

5.13 输出参数

输出参数用于从方法体内把数据传出到调用代码。输出参数有以下要求:

使用方法如下:

void MyMethod(out int val) //方法声明
 { ...}
 ...
int y = 1;               //实参变量
MyMethod(out y);        //方法调用

与引用参数类似,输出参数的形参担当实参的别名。形参和实参都是同一块内存位置的名称。因此,方法内对形参的任何改变在方法执行完成之后通过实参变量都是可见的。

与引用参数不同,输出参数有以下要求:

public void Add2(out int outValue)
{
    int var1 = outValue + 2;  //出错了,使用了未赋值的输出参数outValue
}

下面代码展示使用方法:

class MyClass { public int Val = 20; }

    class Program
    {
        static void MyMethod(out MyClass f1, out int f2)
        {
            f1 = new MyClass();   //创建一个类变量
            f1.Val = 25;        //赋值类字段
            f2 = 15;          //赋值int参数
        }

        static void Main(string[] args)
        {
            MyClass a1 = null;
            int a2;

            MyMethod(out a1, out a2); //调用方法
        }
    }

5.14 参数数组

之前所述的参数类型都 必须严格地一个实参对应一个形参。参数数组则不同,它允许零个或多个实参对应一个特殊地形参。

声明参数数组地方法:

下图展示了 int 型参数数组地声明方法,此例中,形参 inVals 可代表零个或多个 int 实参

5.14.1 方法调用

可使用两种方式为参数数组提供实参

注意,在以上示例中,不需要在调用时使用 params 修饰符。参数数组中修饰符的使用与其他参数类型的模式不一样。

上一篇下一篇

猜你喜欢

热点阅读