一、值參數
1.傳值參數 → 值類型
虛線以上,方法之外;
虛線以上,方法之內。
值參數會創建變量的副本
對值參數的操作不會影響變量的值
class Program
{
static void Main(string[] args)
{
Student stu = new Student();
int y = 100;
stu.AddOne(y);//101
Console.WriteLine(y);//100
}
}
class Student
{
public void AddOne(int x)//值參數x;int值類型
{
x = x + 1;
Console.WriteLine(x);
}
}
2.傳值參數 → 引用類型,並且新創建對象
這種狀況很少見,一般情況都是傳進來引用它的值,而不是連接到新對象去。
class Program
{
static void Main(string[] args)
{
Student stu = new Student() { Name = "Tim" };
SomeMethod(stu);//Tom
Console.WriteLine(stu.Name);//Tim
}
static void SomeMethod(Student stu)
{
stu = new Student() { Name = "Tom" };
Console.WriteLine(stu.Name);
}
}
class Student
{
public string Name { get; set; }
}
Object.GetHashCode()
方法,用於獲取當前對象的哈希代碼,每個對象的 HashCode 都不一樣。
通過 HashCode 來區分兩個 Name 相同的 stu 對象
class Program
{
static void Main(string[] args)
{
Student stu = new Student() { Name = "Tim" };
SomeMethod(stu);//46104728,Tim
Console.WriteLine("{0},{1}", stu.GetHashCode(), stu.Name);//12289376,Tim
}
static void SomeMethod(Student stu)
{
stu = new Student() { Name = "Tim" };
Console.WriteLine("{0},{1}",stu.GetHashCode(),stu.Name);
}
}
class Student
{
public string Name { get; set; }
}
3.傳值參數 → 引用類型,只操作對象,不創建新對象
這種通過傳遞進來的參數修改其引用對象的值的情況,在工作中也比較少見。
因爲作爲方法,其主要輸出還是靠返回值。我們把這種修改參數所引用對象的值的操作叫做方法的副作用(side-effect),這種副作用平時編程時要儘量避免。
class Program
{
static void Main(string[] args)
{
Student stu = new Student() { Name = "Tim" };
UpdateObject(stu);
Console.WriteLine("HashCode={0},Name={1}", stu.GetHashCode(), stu.Name);
}
static void UpdateObject(Student stu)
{
//修改參數所引用着的值的操作,方法的副作用,side-effect
stu.Name = "Tom";
Console.WriteLine("HashCode={0},Name={1}",stu.GetHashCode(),stu.Name);
}
}
class Student
{
public string Name { get; set; }
}
二、引用參數
1.引用參數 → 值類型
引用參數不會爲傳進來的變量創建副本
引用參數直接指向變量所指向的內存地址
class Program
{
static void Main(string[] args)
{
int y = 1;
IWanSideEffect(ref y);
Console.WriteLine(y);//101
}
static void IWanSideEffect(ref int x)
{
x = x + 100;
}
}
class Student
{
public string Name { get; set; }
}
2.引用參數 → 引用類型,創建新對象
class Program
{
static void Main(string[] args)
{
Student outterStu = new Student() { Name = "Tim" };
Console.WriteLine("HashCode={0},Name={1}", outterStu.GetHashCode(), outterStu.Name);
Console.WriteLine("=================================");
IWanSideEffect(ref outterStu);
Console.WriteLine("HashCode={0},Name={1}", outterStu.GetHashCode(), outterStu.Name);
}
static void IWanSideEffect(ref Student stu)
{
stu = new Student() { Name = "Tom" }; //引用參數賦新值
Console.WriteLine("HashCode={0},Name={1}",stu.GetHashCode(),stu.Name);
}
}
class Student
{
public string Name { get; set; }
}
3.引用參數 → 引用類型,不創建新對象只改變對象值
對象的屬性值改變了,但對象的 HashCode 沒有改變—操作的是同一個對象
class Program
{
static void Main(string[] args)
{
Student outterStu = new Student() { Name = "Tim" };
Console.WriteLine("HashCode={0},Name={1}", outterStu.GetHashCode(), outterStu.Name);
Console.WriteLine("======================================");
SomeSideEffect(ref outterStu);
Console.WriteLine("HashCode={0},Name={1}", outterStu.GetHashCode(), outterStu.Name);
}
static void SomeSideEffect(ref Student stu)
{
stu.Name = "Tom";
Console.WriteLine("HashCode={0},Name={1}",stu.GetHashCode(),stu.Name);
}
}
class Student
{
public string Name { get; set; }
}
Notes:
引用類型的引用參數(只操作對象不創建新對象) 與 引用類型的傳值參數(只操作對象不創建新對象) 結果一樣,但內存機理不同。
①傳值參數在內存中創建了實際參數的副本,方法裏面的 stu參數 和 outterStu變量 不是同一個對象,棧內存地址不一樣,但存儲的堆內存地址是相同的,存儲的是Student實例在堆內存中的地址。
②引用參數在內存中沒有創建實際參數的副本,方法裏面的 stu參數 和 outterStu變量 是同一個對象,棧內存地址是一樣的,存儲的是對象在堆內存中的地址。
三、輸出形參
1.輸出參數 → 值類型
①調用帶有輸出參數的方法
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Please input first number:");
string arg1 = Console.ReadLine();
double x = 0;
bool b1 = double.TryParse(arg1, out x);
if (b1 == false)
{
Console.WriteLine("input error");
return;
}
Console.WriteLine("Please input second number:");
string arg2 = Console.ReadLine();
double y = 0;
bool b2 = double.TryParse(arg2, out y);
if (b2 == false)
{
Console.WriteLine("input error");
return;
}
double z = x + y;
Console.WriteLine("{0}+{1}={2}",x,y,z);
}
}
②聲明帶有輸出參數的方法
class Program
{
static void Main(string[] args)
{
double x = 110;
bool b = DoubleParser.TryParse("abd", out x);
if (b == true)
{
Console.WriteLine(x + 1);
}
else
{
Console.WriteLine(x);
}
}
}
class DoubleParser
{
public static bool TryParse(string input, out double result)
{
try
{
result = double.Parse(input);//在方法體內爲輸出參數賦值
return true;
}
catch (Exception)
{
result = 0;
return false;
}
}
}
2.輸出參數 → 引用類型
class Program
{
static void Main(string[] args)
{
Student stu = null;
bool b = StudentFactory.Create("Tim", 34, out stu);
if (b == true)
{
Console.WriteLine("Student {0},age is {1}", stu.Name, stu.Age);
}
}
}
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() { Name = stuName, Age = stuAge };
return true;
}
}
四、數組參數
Notes:
在方法的參數列表當中只能有一個參數是數組參數;而且這個參數必須是參數列表當中的最後一個。
1.使用 params 關鍵字前
class Program
{
static void Main(string[] args)
{
//聲明數組
int[] myintArray = new int[] { 1, 2, 3 };
int result = CalculateSum(myintArray);
Console.WriteLine(result);
}
//計算整型數組中所有元素的和
static int CalculateSum(int[] intArray)
{
int sum = 0;
foreach (var item in intArray)
{
sum += item;
}
return sum;
}
}
2.使用 params 後,不再需要單獨聲明數組
class Program
{
static void Main(string[] args)
{
////聲明數組
//int[] myintArray = new int[] { 1, 2, 3 };
int result = CalculateSum(1,2,3);//不再需要單獨聲明數組
Console.WriteLine(result);//6
}
//計算整型數組中所有元素的和
static int CalculateSum(params int[] intArray)
{
int sum = 0;
foreach (var item in intArray)
{
sum += item;
}
return sum;
}
}
五、具名參數
1.不具名調用示例
class Program
{
static void Main(string[] args)
{
// 不具名調用
PrintInfo("Tim", 34);//string型的name;int型的age
}
static void PrintInfo(string name, int age)
{
Console.WriteLine("Hello {0},you are {1}.",name,age);
}
}
2.具名調用示例
具名參數:參數位置不受參數列表順序約束
提高代碼可讀性
class Program
{
static void Main(string[] args)
{
//具名調用
PrintInfo(age: 34, name: "Tim");//參數位置不受參數列表順序約束
}
static void PrintInfo(string name, int age)
{
Console.WriteLine("Hello {0},you are {1}.",name,age);
}
}
六、可選參數
參數因爲具有默認值而變得“可選”
class Program
{
static void Main(string[] args)
{
//可選參數
PrintInfo();//Hello Tim,you are 34.
}
static void PrintInfo(string name = "Tim", int age = 34)
{
Console.WriteLine("Hello {0},you are {1}.", name, age);
}
}
七、擴展方法(this參數)
1.無擴展方法示例
class Program
{
static void Main(string[] args)
{
double x = 3.14159;
double y = Math.Round(x, 4);//double類型本身沒有Round方法,只能使用Math.Round
Console.WriteLine(y);
}
}
2.有擴展方法示例
class Program
{
static void Main(string[] args)
{
double x = 3.14159;
double y = x.Round(4);//調用擴展方法Round
Console.WriteLine(y);
}
}
static class DoubleExtension
{
public static double Round(this double input, int digits)
{
double result = Math.Round(input, digits);
return result;
}
}
3.LINQ方法示例
判斷集合中是否所有元素都大於10
①沒有使用LINQ擴展方法
class Program
{
static void Main(string[] args)
{
List<int> myList = new List<int>() { 11, 12, 13, 14, 15 };
bool result = AllGreaterThanTen(myList);
Console.WriteLine(result);
}
//判斷集合中是否所有元素都大於10
static bool AllGreaterThanTen(List<int> intList)
{
foreach (var item in intList)
{
if (item<=10)
{
return false;
}
}
return true;
}
}
②使用LINQ擴展方法
class Program
{
static void Main(string[] args)
{
List<int> myList = new List<int>() { 11, 12, 13, 14, 15 };
bool result = myList.All(i => i > 10);//使用擴展方法All(),來判斷集合中所有元素都大於10
Console.WriteLine(result);
}
}