目录
C# 方法
C# 中定义方法
C# 中调用方法
递归方法调用
参数传递
值参数
引用参数
输出参数
常见题
ref 和 out 的区别
方法中参数的类型有几种
扩展方法
对于复杂引用类型参数传递的控制
在C#中定义方法时,需要遵循以下结构:
访问修饰符 返回类型 方法名(参数列表)
{
// 方法体
}
下面是对这些部分的详细说明:
以下是一个简单的示例,演示了如何在C#中定义一个方法:
public class MyClass
{
// 定义一个方法,无返回值,无参数
public void SayHello()
{
Console.WriteLine("Hello, world!");
}
// 定义一个方法,有返回值,带参数
public int Add(int a, int b)
{
return a + b;
}
}
在这个示例中,我们定义了一个名为 MyClass 的类,并在其中定义了两个方法:SayHello 和 Add。SayHello 方法没有返回值,也没有参数,而 Add 方法接受两个整型参数并返回它们的和。
在 C# 中调用方法很简单,只需按照以下格式编写代码即可:
// 创建类的实例
MyClass myObject = new MyClass();
// 调用无返回值、无参数的方法
myObject.SayHello();
// 调用有返回值、带参数的方法
int result = myObject.Add(3, 4);
Console.WriteLine("The result is: " + result);
在这个示例中,我们首先创建了 MyClass 类的一个实例 myObject。然后我们调用了 SayHello 方法,因为它没有返回值和参数,所以调用方式很简单。接着调用了 Add 方法,并将返回值存储在 result 变量中,最后打印出结果。
需要注意的是,如果方法是静态方法(使用 static 关键字修饰),则可以通过类名直接调用,而不需要创建类的实例。例如:
// 调用静态方法
int result = MyClass.StaticAdd(3, 4);
Console.WriteLine("结果是:: " + result);
在这个示例中,StaticAdd 是一个静态方法,我们直接使用类名 MyClass 来调用它,而不需要创建类的实例。
在C#中,可以使用递归来实现方法调用自身的功能。递归方法通常用于解决可以被分解为相似子问题的问题,比如树的遍历、阶乘计算等。
以下是一个简单的示例,演示了如何在C#中定义和调用递归方法:
public class RecursionExample
{
// 递归方法计算阶乘
public int Factorial(int n)
{
// 基本情况:当 n 等于 0 或 1 时,阶乘为 1
if (n == 0 || n == 1)
{
return 1;
}
// 递归情况:调用自身来计算 n 的阶乘
else
{
return n * Factorial(n - 1);
}
}
}
class Program
{
static void Main()
{
RecursionExample example = new RecursionExample();
// 调用递归方法计算阶乘
int result = example.Factorial(5);
Console.WriteLine("5的阶乘是: " + result);
}
}
在这个示例中,我们定义了一个 RecursionExample 类,并在其中定义了一个名为 Factorial 的递归方法,用于计算给定整数的阶乘。在 Factorial 方法内部,我们首先检查基本情况(n等于0或1),然后在递归情况下调用自身来计算阶乘。在 Main 方法中,我们创建了 RecursionExample 类的实例,并调用了 Factorial 方法来演示递归调用。
需要注意的是,在使用递归时,务必确保存在终止条件,避免无限循环调用。
在C#中,有值参数、引用参数和输出参数这三种向方法传递参数的方式。
值参数是最常见的参数传递方式。当你向方法传递值参数时,会创建一个新的变量,该变量存储了原始值的副本,而不会影响原始值。对于值参数,形参和实参使用的是两个不同的内存位置。
这种方式确保了实参数据的安全性,因为方法对形参的任何修改都仅限于方法范围内,不会对原始数据产生影响。这也意味着,对形参的任何修改都不会传递回到调用者处。
因此,按值传递参数适用于那些不需要修改原始数据的情况,同时也能确保原始数据的安全。
下面是一个示例:
public void IncrementValue(int number)
{
number++;
}
在C#中,按引用传递参数时,方法将直接操作原始数据的内存位置,而不是创建一个副本。
这意味着,当使用引用参数时,对参数的任何修改都会影响到原始数据,因为实际参数和形参指向相同的内存位置。这种方式允许方法能够修改原始数据,并将修改后的值传递回调用者处。
引用参数适用于那些需要对原始数据进行修改并且把修改后的值传递回调用者的情况。与按值传递不同,按引用传递参数能够在方法内部直接影响到原始数据,因此需要谨慎使用,以避免意外的数据修改。
在C#中,通过在参数前面添加 ref 关键字来声明引用参数。下面是一个示例:
public void IncrementValue(ref int number)
{
number++;
}
输出参数用于从方法中返回多个值。
在C#中,通过在参数前面添加 out 关键字来声明输出参数。与引用参数不同,输出参数在方法内部不需要对其进行初始化,而是在方法内部为其赋值,这个被赋予的值会传递回到调用者处。
public void GetValues(out int x, out int y)
{
x = 10;
y = 20;
}
使用这三种参数传递方式可以根据需要在方法间传递数据,并灵活地处理方法对数据的修改和返回。
using System;
public class ParameterExample
{
// 值参数示例
public void IncrementValue(int number)
{
number++;
}
// 引用参数示例
public void IncrementValueRef(ref int number)
{
number++;
}
// 输出参数示例
public void GetValues(out int x, out int y)
{
x = 10;
y = 20;
}
}
class Program
{
static void Main()
{
ParameterExample example = new ParameterExample();
// 值参数示例
int value = 10;
example.IncrementValue(value);
Console.WriteLine("值参数方法调用后的值: " + value); // 输出为 10
// 引用参数示例
int refValue = 10;
example.IncrementValueRef(ref refValue);
Console.WriteLine("引用参数方法调用后的值: " + refValue); // 输出为 11
// 输出参数示例
int result1, result2;
example.GetValues(out result1, out result2);
Console.WriteLine("结果1的值: " + result1); // 输出为 10
Console.WriteLine("结果2的值: " + result2); // 输出为 20
}
}
方法中参数的类型有三种
在 C# 中,扩展方法允许你向现有的类添加新的方法,而无需修改原始类的定义,也不需要继承该类。这对于在不可修改代码的情况下向现有类型添加功能非常有用。
规则:
using System;
// 静态类中定义扩展方法
public static class StringExtensions
{
// 扩展方法必须是静态方法,并且第一个参数以 this 关键字开头,表示要扩展的目标类型
public static int WordCount(this string str)
{
return str.Split(new char[] { ' ', '.', '?' }, StringSplitOptions.RemoveEmptyEntries).Length;
}
}
class Program
{
static void Main()
{
string text = "Hello, how are you?";
int count = text.WordCount(); // 调用扩展方法
Console.WriteLine("字数: " + count); // 输出结果: 字数: 4
}
}
在上面的示例中,我们创建了一个静态类 StringExtensions,其中包含了一个扩展方法 WordCount。这个方法对 string 类型进行了扩展,可以方便地计算字符串中单词的个数。在 Main 方法中,我们演示了如何调用这个扩展方法,并输出了结果。
所谓复杂,是参数是数组或集合类型,或者参数包含这些类型数据,这种情况下上面的方法不能保证参数数据不被修改,因为即使对象为只读的,但是对象中的数组或集合字段(属性)还是可以修改的。
1、集合参数(包含集合字段的引用参数也一样)
.net 4.5以前版本可以使用不包含修改集合元素方法的接口来代替具体集合类型。例如使用IEnumerable
2、数组参数
没有好的办法保护数组类型参数不被修改,所以尽量避免使用数组类型作为方法参数,除非用到可选参数时候。
更多内容参考:C# 中数组作为参数传递的问题