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

八、总结

在这里插入图片描述

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