C#基礎語法 — (8)傳值、輸出、引用、數組、具名、可選參數、擴展方法


一、值參數

在這裏插入圖片描述

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);
        }
    } 

八、總結

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章