一.传值
值类型
传入方法中相当于是对传入的参数创建了一个值相等的副本
class Programme
{
static void Main(string[] args)
{
int y = 100;
Complex.Add(y);
Console.WriteLine(y);
}
}
class Complex
{
public static void Add(int x)
{
x = x + 1;
Console.WriteLine(x);
}
}
//输出的结果为 101 100说明y的值并没有被改变
引用类型
原理也是一样,先创建一个副本,但是副本所指向的是传值参数的对象地址,如果重新给对象赋值的话就会改变副本的引用对象
class Programme
{
static void Main(string[] args)
{
Student stu = new Student() { Name = "Tom" };
Set_Name(stu);
Console.WriteLine("{0},{1}",stu.Name,stu.Name.GetHashCode());
}
public static void Set_Name(Student stu)
{
stu.Name = "tim";
//stu = new Student(){Name = "chengzhirui"} 这样会改变引用对象,一般不常用
Console.WriteLine("{0},{1}",stu.Name,stu.Name.GetHashCode());
}
}
class Student
{
public string Name { get; set; }
}
/*
tim,1344150661
tim,1344150661
*/
二.引用参数
用ref修饰的形参,不创建新的副本而是传入参数的存储位置,必须先进行赋值操作
值类型
class Programme
{
static void Main(string[] args)
{
int y = 100;
Add(ref y);
Console.WriteLine(y);
}
public static void Add(ref int x)
{
x +=1;
Console.WriteLine(x);
}
引用类型
class Programme
{
static void Main(string[] args)
{
Student stu = new Student() { Name = "chengzhirui" };
Console.WriteLine("{0} {1}", stu.GetHashCode(), stu.Name);
Console.WriteLine("-------------------------------");
SideEffect(ref stu);
Console.WriteLine("{0} {1}", stu.GetHashCode(), stu.Name);
}
public static void SideEffect(ref Student stu)
{
stu.Name = "cheng";
Console.WriteLine("{0} {1}",stu.GetHashCode(),stu.Name);
}
}
class Student
{
public string Name { get; set; }
}
/*
* 46104728 chengzhirui
-------------------------------
46104728 cheng
46104728 cheng
*/
值得注意的是,ref这里加和没加上输出结果相同,但是内部存储是有差异的,加了ref的栈中的地址都是同一个,而没加地址的是栈中会有一个复制品
三.输出参数
用out修饰符修饰的参数,主要功能就是输出除了返回值以外的参数
值类型
以下是ref和out的对比
class Program
{
static void ModifyRefParam(ref int x)
{
x = x * 2; // 可以修改传递的参数的值
}
static void ModifyOutParam(out int y)
{
//在方法体内被赋值之前不能被使用
//如果在这一行添加console.writeline(y)会编译出错
y = 10; // 必须在方法内赋值
}
static void Main()
{
int a = 5;
int b = 2;
ModifyRefParam(ref a);
Console.WriteLine($"After ModifyRefParam, a = {a}"); // 输出: After ModifyRefParam, a = 10
// 在调用方法时不需要初始化 out 参数
ModifyOutParam(out b);
Console.WriteLine($"After ModifyOutParam, b = {b}"); // 输出: After ModifyOutParam, b = 10
}
}
引用类型
class Programme
{
static void Main(string[] args)
{
Student stu = null;
bool result = StudentFactory.Factory("wangwu", 100,out stu);
Console.WriteLine(result);
}
}
class Student
{
public int Age { get; set; }
public string Name { get; set; }
}
class StudentFactory
{
public static bool Factory(string name,int age,out Student stu)
{
stu = null;
if (age > 200)
return false;
if(name==null)
return false;
stu = new Student() { Name = name,Age = age};
return true;
}
}
内部存储模式和ref是近乎一致的,
不同的是在程序中的限制,输出类型的函数返回值必须在对输出对象进行复制后才能用return返回
而ref则不需要,我的理解就是out只是ref的一种多态
数组参数
class Programme
{
static void Main(string[] args)
{
int[] stu = new int[] {1,2, 3, 4, 5};
Print(stu);
int sum = ParamsPrint(1, 2, 3);
Console.WriteLine(sum);
}
public static void Print(int[] stu)
{
foreach(var st in stu)
{
Console.WriteLine(st);
}
}
public static int ParamsPrint(params int[] stud )
{
int sum = 0;
foreach(var st in stud)
{
sum += st;
}
return sum;
}
}
可以用params修饰词省略数组创建的方式,也就是说可以直接忽略数组的创建过程,以至于直接在使用函数的时候就传入形参
但是params参数必须是参数列表的最后一个
具名参数
就是可以在调用函数的时候,给传入的参数前面加上形参的名字,达到索引的效果
class Programme
{
static void Main(string[] args)
{
PrintInfo(name: "chengzhri", age: 20);
}
public static void PrintInfo(string name,int age)
{
Console.WriteLine("my name is{0},im {1} years old", name, age);
}
}
还有一种就是默认参数(可以不传递参数)
class Programme
{
static void Main(string[] args)
{
PrintInfo();
}
public static void PrintInfo(string name = "chengzhirui",int age = 20)
{
Console.WriteLine("my name is{0},im {1} years old", name, age);
}
}
扩展方法
就是在不修改目标源代码的情况下对方法进行扩展,
1.必须是被public static 所修饰的
2.必须是形参列表的第一个
3.必须是由静态类引出,一般的名称是SomeTypeExtension
class Programme
{
static void Main(string[] args)
{
double x = 3.1415926;
double y = x.Round(4);
Console.WriteLine(y);
}
}
static class DoubleExtension
{
public static double Round(this double input,int i)
{
return Math.Round(input,i);
}
}