傳值引數
宣告時不帶修飾符的形參為值形參,相當於方法內的區域性變數,初始化的值來自呼叫該方法時提供的實參。
當傳值引數為值型別時,值形參相當於只複製實參的副本,對與值形參的改動不會影響到實參。
當傳值引數為引用型別,並建立新物件覆蓋形參時,對形參的修改同樣不會影響實參。
當傳值引數為引用型別,且只操作物件,不建立新物件時,對形參的修改影響實參。一般把修改引數所引用的物件的值的操作稱為副引用(side-effect)
class Program
{
static void Main(string[] args)
{
Student stu = new Student();
int y = 100;
stu.AddOne(y); //形參x複製實參y的值,修改x的值不會影響y
Console.WriteLine(y);
stu.Name = "Mosen";
SomeMethod(stu);
Console.WriteLine(stu.Name);
UpdataObject(stu);
Console.WriteLine("{0}, {1}", stu.GetHashCode(), stu.Name);
}
static void SomeMethod(Student stu)
{
stu = new Student() { Name="Tom"}; //此處stu指向新的Student物件
Console.WriteLine(stu.Name);
}
static void UpdataObject(Student s) //透過修改 s 更新實參 stu 的值
{
s.Name = "Owmt";
Console.WriteLine("{0}, {1}", s.GetHashCode(), s.Name);
}
}
class Student
{
public string Name { get; set; }
public void AddOne(int x)
{
x += 1;
Console.WriteLine(x);
}
}
引用引數
引用形參是用 ref 修飾符修飾的形參。引用形參不建立新的儲存位置,而是直接指向傳進來的實參所指向的記憶體地址。變數在作為引用形參傳遞之前,須明確賦值。
class Program
{
static void Swap(ref int x, ref int y) //使用ref修飾形參,對x、y的改動會影響Main方法中的x、y
{
int temp = x;
x = y;
y = temp;
}
static void IWantSideEffect(ref Student stu) //對stu賦值會影響到 outterStu 指向的例項資料
{
stu = new Student() { Name = "Tom" };
Console.WriteLine("HashCode={0}, Name={1}", stu.GetHashCode(), stu.Name);
}
static void SomeSideEffect(ref Student stu) //影響到 outterStu2 指向的例項資料的內容
{
stu.Name = "Tom";
Console.WriteLine("HashCode={0}, Name={1}", stu.GetHashCode(), stu.Name);
}
static void Main(string[] args)
{
int x = 10;
int y = 20;
Swap(ref x, ref y);
Console.WriteLine(x + " " + y);
Student outterStu = new Student() { Name = "Tim" };
Console.WriteLine("HashCode={0}, Name={1}", outterStu.GetHashCode(), outterStu.Name);
Console.WriteLine("--------------");
IWantSideEffect(ref outterStu);
Console.WriteLine("HashCode={0}, Name={1}\n", outterStu.GetHashCode(), outterStu.Name);
Student outterStu2 = new Student() { Name = "Tim" };
Console.WriteLine("HashCode={0}, Name={1}", outterStu2.GetHashCode(), outterStu2.Name);
Console.WriteLine("--------------");
SomeSideEffect(ref outterStu2);
Console.WriteLine("HashCode={0}, Name={1}", outterStu2.GetHashCode(), outterStu2.Name);
}
}
class Student
{
public string Name { get; set; }
}
輸出引數
使用out修飾符宣告的形參為輸出形參,和引用形參類似,輸出形參不建立新的儲存位置,和實參指向同一記憶體位置。使用輸出引數時,方法體內必須要有對輸出變數進行賦值的操作。out修飾符顯示指出,方法的副作用是透過引數向外輸出值。
class Program
{
static void Main(string[] args)
{
double x = 0;
bool res = DoubleParse.TryParse("724", out x);
if (res)
{
Console.WriteLine(x+1);
}
Student stu = null;
bool res2 = StudentFactory.Create("Tim", 25, out stu);
if(res2)
{
Console.WriteLine("Student {0}, Age is {1}", stu.Name, stu.Age);
}
}
}
class DoubleParse
{
public static bool TryParse(string input, out double result)
{
try
{
result = Double.Parse(input);
return true;
}
catch
{
result = 0;
return false;
}
}
}
class Student
{
public int Age { get; set; }
public string Name { get; set; }
}
class StudentFactory
{
public static bool Create(string stuName, int stuAge, out Student result)
{
result = null;
if (string.IsNullOrEmpty(stuName))
{
return false;
}
if(stuAge < 20 || stuAge > 80)
{
return false;
}
result = new Student();
result.Name = stuName;
result.Age = stuAge;
return true;
}
}
注:使用引用引數時,呼叫方法處的實參需要明確賦值,更傾向於對實參的值進行修改。而輸出引數在呼叫方法之前不一定需要明確賦值,更傾向於呼叫方法後對實參進行賦值。語義上 ref 是“改變”,而 out 是為了“輸出”。
陣列引數
形參列表的最後一個引數,用 params 修飾。
class Program
{
static void Main(string[] args)
{
int res = CalculateSum(1,2,3,4,5); //不必提前宣告陣列,而是直接輸入陣列元素即可
Console.WriteLine(res);
string str = "Tim;Tom,Amy.Lisa";
string[] splitRes = str.Split(';', ',', '.');
foreach (string s in splitRes)
{
Console.WriteLine(s);
}
}
static int CalculateSum(params int[] intArray)
{
int sum = 0;
foreach(var item in intArray)
{
sum += item;
}
return sum;
}
}
具名引數
可以提高程式碼可讀性且引數的位置不受約束。
class Program
{
static void Main(string[] args)
{
PrintInfo(age: 23, name:"Tim");
}
static void PrintInfo(string name, int age)
{
Console.WriteLine("Name: {0}\nAge: {1}", name, age);
}
}
可選引數
引數具有預設值而變得“可選”。
class Program
{
static void Main(string[] args)
{
PrintInfo();
}
static void PrintInfo(string name = "Tim", int age = 23)
{
Console.WriteLine("Name: {0}\nAge: {1}", name, age);
}
}
擴充套件方法(this引數)
用於為目標資料型別“追加”方法:
1、方法必須是公有、靜態(public static)。
2、必須是形參列表中的第一個,由 this 修飾。
3、必須由一個靜態類(一般名為 xxxExtension)統一收納相應的型別的擴充套件方法。
class Program
{
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 digits)
{
double result = Math.Round(input, digits);
return result;
}
}