C#學習筆記-方法引數、擴充套件方法

owmt發表於2024-05-06

傳值引數

  宣告時不帶修飾符的形參為值形參,相當於方法內的區域性變數,初始化的值來自呼叫該方法時提供的實參。

  當傳值引數為值型別時,值形參相當於只複製實參的副本,對與值形參的改動不會影響到實參。

  當傳值引數為引用型別,並建立新物件覆蓋形參時,對形參的修改同樣不會影響實參。

  當傳值引數為引用型別,且只操作物件,不建立新物件時,對形參的修改影響實參。一般把修改引數所引用的物件的值的操作稱為副引用(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;
    }
}

相關文章