C# 教程 在线

2386C# 方法

扩展方法

扩展方法可以实现在不需要修改目标类,也不需要继承目标类的情况下为其添加一个方法。

规则:

  • 1、扩展类必须为静态类,扩展方法必须为静态方法。
  • 2、扩展方法的第1个形参开头必须使用 “this” 关键字然后再填写扩展的目标类。
  • 3、如果需要接收参数则从第2个参数开始算起,第1个参数在真正调用方法时是隐藏的。
public static class ExtensionString
{
    //向 String 类扩展一个统计单词数量的方法
    public static int CountWord(this String str)
    {
        return str.Split(' ').Length;
    }
}

class MainClass
{
    public static void Main(string[] args)
    {
        Console.WriteLine("单词数量:" + "Hello World".CountWord()); //没有参数
    }
}

2385C# 方法

按值传递参数的问题:

为什么即使在函数内改变了值,值也没有发生任何的变化呢?

在交换之前,a 的值:100
在交换之前,b 的值:200
在交换之后,a 的值:100
在交换之后,b 的值:200

解析:

调用一个方法时相当于复制一个对象到新分配的内存中,方法完毕对象也就del了,两个变量是不同的两个地址,a只不过是栈里的临时变量而已,和主函数里的变量没有关系,因此不会改变b的值。

而指针和引用直接访问内存地址,故直接修改所指向的对象,两者指向同一变量。

2384C# 方法

方法中参数的类型有三种

in型参数

int 型参数通过值传递的方式将数值传入方法中,即我们在Java中常见的方法。

ref型参数

该种类型的参数传递变量地址给方法(引用传递),传递前变量必须初始化。

该类型与out型的区别在与:

  • 1).ref 型传递变量前,变量必须初始化,否则编译器会报错, 而 out 型则不需要初始化
  • 2).ref 型传递变量,数值可以传入方法中,而 out 型无法将数据传入方法中。换而言之,ref 型有进有出,out 型只出不进。

out 型参数

与 ref 型类似,仅用于传回结果。

注意:

1). out型数据在方法中必须要赋值,否则编译器会报错。

eg:如下图若将代码中的sum1方法的方法体

改为 a+=b; 则编译器会报错。原因:out 型只出不进,在没给 a 赋值前是不能使用的

改为 b+=b+2; 编译器也会报错。原因:out 型数据在方法中必须要赋值。

2). 重载方法时若两个方法的区别仅限于一个参数类型为ref 另一个方法中为out,编译器会报错

eg:若将下面的代码中将方法名 vsum1 改为 sum(或者将方法名 sum 改为 sum1),编译器会报错。

Error 1 Cannot define overloaded method ‘sum’ because it differs from another method only on ref and out 

原因:参数类型区别仅限于 为 ref 与为 out 时,若重载对编译器而言两者的元数据表示完全相同。

class C
{
    //1. in型参数
    public void sum(int a, int b) {
        a += b;
    }
    //2. ref型参数
    public void sum(ref int a, int b)
    {
        a += b;
    }
    //3. out型参数
    public void sum1(out int a, int b)
    {
        a = b+2;
    }
    public static void Main(string[] args)
    {
        C c = new C();
        int a = 1, b = 2;
        c.sum(a,b);
        Console.WriteLine("a:{0}", a);
        a = 1; b = 2;
        c.sum(ref a, b);
        Console.WriteLine("ref a:{0}", a);
        a = 1; b = 2;
        c.sum1(out a, b);
        Console.WriteLine("out a:{0}", a);
    }
}

输出结果: 

从代码也可以看出,int 型参数为值传递,所以当将变量 a 传入方法时,变量 a 的值并不会发生变化。而 ref 型参数,由于是引用传递,将变量的值和地址都传入方法中故变量值改变。out 型无法将变量的值传入。但可以将变量的地址传入并为该地址上的变量赋值。

2383C# 方法

ref 和 out 的区别

一个用关键字 ref 标示,一个用 out 标示。

牵扯到数据是引用类型还是值类型。

一般用这两个关键字你是想调用一个函数将某个值类型的数据通过一个函数后进行更改。传 out 定义的参数进去的时候这个参数在函数内部必须初始化。否则是不能进行编译的。ref 和 out 都是传递数据的地址,正因为传了地址,才能对源数据进行修改。

一般情况下不加 ref 或者 out 的时候,传值类型的数据进去实际上传进去的是源数据的一个副本,也就是在内存中新开辟了一块空间,这里面存的值是与源数据相等的,这也就是为什么在传值类型数据的时候你如果不用 return 是无法修改原值的原因。但是你如果用了 ref,或者 out,这一切问题都解决了,因为他们传的是地址。

out 比起 ref 来说,还有一个用法就是可以作为多返回值来用,都知道函数只能有一个返回值,C#里,如果你想让一个函数有多个返回值,那么OUT能很容易解决。

2382C# 方法

局部变量是只能在函数内部访问到的,而字段可以在整个类中访问到,在外部声明可以在其他方法使用的时候进行调用,比如有另外一个方法想要调用max值即可直接使用;

using System;

namespace CalculatorApplication
{
    class NumberManipulator
    {
        int max;
        public int FindMax(int num1, int num2)
        {
            /* 局部变量声明 */
            int result;

            if (num1 > num2)
                result = num1;
            else
                result = num2;

            return result;
        }
        public  int getmax(int max)//该方法同样可以获取max中的值
        {
            return max;
        }
        static void Main(string[] args)
        {
            /* 局部变量定义 */
            int a = 100;
            int b = 200;
            NumberManipulator n = new NumberManipulator();

            //调用 FindMax 方法
            n.max = n.FindMax(a, b);
            Console.WriteLine("最大值是: {0}", n.max );
            Console.ReadLine();
        }
    }
}