C# 入门教程(三):详解字段、属性、索引器及各类参数与扩展方法

文章目录

  • 一、字段、属性、索引器、常量
    • 1.字段
    • 2.属性
      • [2.1 什么是属性](#2.1 什么是属性)
      • [2.2 属性的声明](#2.2 属性的声明)
      • [2.3 属性与字段的关系](#2.3 属性与字段的关系)
    • [3 索引器](#3 索引器)
    • [4. 常量](#4. 常量)
  • [二、传值 输出 引用 数组 具名 可选参数,扩展方法](#二、传值 输出 引用 数组 具名 可选参数,扩展方法)
    • [2.1 传值参数](#2.1 传值参数)
      • [2.1.1 值类型 传参](#2.1.1 值类型 传参)
      • [2.1.2 引用类型 传参](#2.1.2 引用类型 传参)
    • [2.2 引用参数](#2.2 引用参数)
      • [2.2.1 引用参数-值类型 传参](#2.2.1 引用参数-值类型 传参)
      • [2.2.2 引用参数 - 引用类型 传参](#2.2.2 引用参数 - 引用类型 传参)
    • [2.3 输出参数](#2.3 输出参数)
      • [2.3.1 输出参数-值类型](#2.3.1 输出参数-值类型)
      • [2.3.2 输出参数-引用类型](#2.3.2 输出参数-引用类型)
    • [2.4 数组参数 (params)](#2.4 数组参数 (params))
    • [2.5 具名参数](#2.5 具名参数)
    • [2.6 可选参数](#2.6 可选参数)
    • [2.7 扩展方法(this参数)](#2.7 扩展方法(this参数))
    • [2.8 各种参数的使用场景总结](#2.8 各种参数的使用场景总结)

一、字段、属性、索引器、常量

1.字段

  • 什么是字段

    • 字段(field)是一种表示与对象或类型(类与结构体)关联的变量"字段是类型的成员,旧称"成员变量
    • 与对象关联的字段亦称"实例字段"
    • 与类型关联的字段称为"静态字段"",由static修饰
  • 字段的声明

    • 参见C#语言定义文档
    • 尽管字段声明带有分号但它不是语句
    • 字段的名字一定是名词
  • 字段的初始值

    • 无显式初始化时,字段获得其类型的默认值,所以字段"永远都不会未被初始化"
    • 实例字段初始化的时机--对象创建时
    • 静态字段初始化的时机--类型被加载(load )时
    csharp 复制代码
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                //实例化一个学生
                Student student = new Student();
                student.Age = 10;
                student.Score = 100;
    
                Console.WriteLine(student.Score);
    
    
                //实例化100个学生,求平均年龄和平均分
                List<Student> studentList = new List<Student>();
                for (int i = 0; i < 100; i++) { 
                    Student stu = new Student();
                    stu.Age = 25;
                    stu.Score = i+10;
                    studentList.Add(stu);
                }
    
                int totalAge = 0;
                int totalScore = 0;
    
                foreach (var stu in studentList)
                {
                    totalAge += stu.Age;
                    totalScore += stu.Score;
                }
    
                Student.AverageAge = totalAge/Student.Amount;
                Student.AverageScore = totalScore/Student.Amount;
    
                Student.ReportAverageScore();
                Student.ReportAverageAge();
    
    
            }
        }
    
        class Student
        {
    	    public int Age;
    		public int Score;
            // 字段初始化器
    		public int AgeInit = 30;
    		
    		//平均年龄
    		public static int AverageAge;
    		
    		//平均分
    		public static int AverageScore;
    		
    		//静态字段的初始化器
    		public static int Amount = 0;
    
            public Student()
            {
                Student.Amount++;
            }
    
            public static void ReportAverageAge()
            {
                Console.WriteLine(Student.AverageAge);
            }
    
            public static void ReportAverageScore()
            {
                Console.WriteLine(Student.AverageScore);
            }
    
            public void ReportAmount(int score)
            {
                Console.WriteLine(Student.Amount);
            }
        }
    }
  • 只读字段

    • 实例只读字段
    csharp 复制代码
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                StudentOne studentOne = new StudentOne(35);
                Console.WriteLine( studentOne.ID);
                
                //错误:给只读字段赋值将会报错
                studentOne.ID = 100;
            }
        }
    
        class StudentOne
        {
        	//学生id设置为只读字段
            public readonly int ID;
            
            public string Name;
            public int Age;
            
           //只读字段实例化构造器
            public StudentOne(int Id)
            {
            	//只有在实例化的时候才能赋值
                this.ID = Id;
            }
        }
    }
    • 静态只读字段
    csharp 复制代码
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                Console.WriteLine(Brush.DefaultColor.Red);
     			Console.WriteLine(Brush.DefaultColor.Green);
            }
        }
    
       
        struct Color
        {
            public int Red;
            public int Green;
            public int Blue;
        }
    
        class Brush
        {
            //声明一个静态只读字段
            // public static readonly Color DefaultColor = new Color() { Red = 0, Green = 0, Blue = 0 };
    
            //静态只读字段构造器
            public static readonly Color DefaultColor;
            static Brush(){
                Brush.DefaultColor = new Color() { Red = 0, Green = 0, Blue = 0 };
            }
        }
    }
    	

2.属性

2.1 什么是属性

  • 属性(property)是一种用于访问对象或类型的特征的成员,特征反映了状态
  • 属性是字段的自然扩展,
    • 从命名上看,field更偏向于实例对象在内存中的布局,property更偏向于反映现实世界对象的特征
    • 对外:暴露数据,数据可以是存储在字段里的,也可以是动态计算出来的
    • 对内:保护字段不被非法值"污染"属性由Get/Set方法对进化而来
  • 又一个"语法糖"--属性背后的秘密
csharp 复制代码
	using System;
	using System.Collections.Generic;
	using System.Linq;
	using System.Text;
	using System.Threading.Tasks;
	
	namespace PropertyExample
	{
	    class PropertyExample
	    {
	        static void Main(string[] args)
	        {
	            //字段的定义使用
	            try
	            {
	                Student student = new Student();
	                student.setAge(30);
	
	                Student student2 = new Student();
	                student2.setAge(50);
	
	                Student student1 = new Student();
	                student1.setAge(80);
	
	                int avgAge = (student.getAge() + student2.getAge() + student1.getAge()) / 3;
	                Console.WriteLine(avgAge);
	            }
	            catch (Exception ex)
	            {
	                Console.WriteLine(ex.Message);
	            }
	
	
	            //属性的使用
	            try
	            {
	                Student student = new Student();
	                student.Age = 25;
	
	                Student student2 = new Student();
	                student2.Age = 40;
	
	                Student student1 = new Student();
	                student1.Age = 50;
	
	                int avgAge = (student.Age + student2.Age + student1.Age) / 3;
	                Console.WriteLine(avgAge);
	            }
	            catch (Exception ex)
	            {
	                Console.WriteLine(ex.Message);
	            }
	        }
	    }
	
	    class Student
	    {
	        private int age;
	
	        //原始的字段获取和赋值
	        public int getAge()
	        {
	            return this.age;
	        }
	
	        public void setAge(int age)
	        {
	            if (age > 100 || age < 0)
	            {
	                throw new Exception("Age has Error");
	            }
	            else
	            {
	                this.age = age;
	            }
	        }
	
	
	        //演变成属性
	        public int Age
	        {
	            get
	            {
	                return this.age;
	            }
	
	            set
	            {
	                if (value >= 0 && value < 120)
	                {
	                    this.age = value;
	                }
	                else
	                {
	                    throw new Exception("Age is Error");
	                }
	            }
	        }
	
	    }
	}

反编译分析:

输入: ildasm , 打开反编译器

打开文件,找到对应的dll文件打开,如下:

2.2 属性的声明

  • 完整声明--后台(back)成员变量与访问器(注意使用code snippet和refactor工具)
csharp 复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PropertyExample
{
    class PropertyExample
    {
        static void Main(string[] args)
        {
          
            //实例属性
            try
            {
                Student student = new Student();
                student.Age = 25;
                Console.WriteLine(student.Age );
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

			//静态属性
            try
            {
                Student.Amount = 80;
                Console.WriteLine(Student.Amount);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }

    class Student
    {
    	//实例属性
        public int Age
        {
            get
            {
                return this.age;
            }

            set
            {
                if (value >= 0 && value < 120)
                {
                    this.age = value;
                }
                else
                {
                    throw new Exception("Age is Error");
                }
            }
        }


		//静态属性
        private static int amount;

        public static int Amount
        {
            get { return amount; }
            set
            {
                if (value > 0)
                {
                    amount = value;
                }
                else
                {
                    throw new Exception("amount is error");
                }
            }
        }
    }
}
  • 简略声明--只有访问器(查看IL代码 )
csharp 复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PropertyExample
{
    class PropertyExample
    {
        static void Main(string[] args)
        {
            Student student3 = new Student();
            student3.ageInit = 50;
            Console.WriteLine(student3.ageInit);
        }
    }

    class Student
    {
        public int ageInit { get; set; }

    }
}
  • 动态计算值的属性
csharp 复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PropertyExample
{
    class PropertyExample
    {
        static void Main(string[] args)
        {
            Student student5 = new Student();
            student5.Age = 50;
            Console.WriteLine(  student5.CanWork);
        }
    }

    class Student
    {
        //年龄属性
        public int Age
        {
            get
            {
                return this.age;
            }

            set
            {
                if (value >= 0 && value < 120)
                {
                    this.age = value;
                }
                else
                {
                    throw new Exception("Age is Error");
                }
            }
        }
		
		//能否工作属性
        public bool CanWork
        {
            get
            {
                if (this.age > 18)
                {
                    return true;
                }
                else
                {
                    return false;
                }

            }
        }
    }
}
  • 注意实例属性和静态属性

  • 属性的名字一定是名词

  • 只读属性--只有getter没有setter

    • 尽管语法上正确,几乎没有人使用"只写属性",因为属性的主要目的是通过向外暴露数据而表示对象/类型的状态
csharp 复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PropertyExample
{
    class PropertyExample
    {
        static void Main(string[] args)
        {
        	//ageInit 是只读属性,不能赋值
            Student student3 = new Student();
            Console.WriteLine(student3.ageInit);

			//score 属性不允许外部赋值,只能内部赋值
            Student student4 = new Student();
            student4.setScore();
            Console.WriteLine(student4.score);
        }
    }

    class Student
    {
    	//只读属性,没有set方法
        public int ageInit { get; }

		//有set方法,但是是私有的,只能内部进行赋值
        public int score {  
            get;
            private set;
        }

		//	内部赋值
        public void setScore()
        {
            this.score = 100;
        }
    }
}

2.3 属性与字段的关系

  • 一般情况下,它们都用于表示实体(对象或类型)的状态
  • 属性大多数情况下是字段的包装器(wrapper)
  • 建议:永远使用属性(而不是字段)来暴露数据,即字段永远都是private或protected的

3 索引器

  • 什么是索引器
    • 索引器 (indexer) 是这样一种成员:它使对象能够用与数组相同的方式(即使用下标)进行索引
  • 索引器的声明
    • 参见C#语言定义文档
    • 注意:没有静态索引器
csharp 复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PropertyExample
{
    class PropertyExample
    {
        static void Main(string[] args)
        {
            Studentcj student6 = new Studentcj();
            var aa = student6["xiaoming"];

            Console.WriteLine(aa==null);

            student6["xiaoming"] = 60;
            Console.WriteLine(student6["xiaoming"]);
        }
    }

    class Studentcj
    {
    	//定义一个集合
        private Dictionary<string,int> scoreDictionary = new Dictionary<string,int>();

        public int? this[string subject]
        {
            get {
            	// 检测是否存在,存在则返回具体值,不存在返回null
                if (this.scoreDictionary.ContainsKey(subject))
                {
                    return this.scoreDictionary[subject];
                }
                else
                {
                    return null;
                }
            }

            set
            {
            	// 设置的值为null,直接异常
                if (value.HasValue == false)
                {
                    throw new Exception("值不能为空");
                }
                //检测是否有值,有值则覆盖,没有则新增
                if (this.scoreDictionary.ContainsKey(subject))
                {
                    this.scoreDictionary[subject] = value.Value;
                }
                else
                {
                    this.scoreDictionary.Add(subject, value.Value);
                }
            }

        }
    }
}

4. 常量

  • 什么是常量

    • 常量(constant)是表示常量值(即,可以在编译时计算的值)的类成员

    • 常量隶属于类型而不是对象,即没有"实例常量"

      • "实例常量"的角色由只读实例字段来担当
    • 注意区分成员常量与局部常量

    csharp 复制代码
    namespace consetExample
    {
         class Program
        {
            static void Main(string[] args)
            {
                // 局部常量
                const int Age = 35; 
    
                Console.WriteLine(baidu.url);
                
            }
        }
    
        class baidu
        {
            //成员常量
    
            public const string url = "www.baidu.com";
        }
    }
  • 常量的声明

  • 各种"只读"的应用场景

    • 为了提高程序可读性和执行效率--常量
    • 为了防止对象的值被改变一-只读字段
    • 向外暴露不允许修改的数据--只读属性(静态或非静态),功能与常量有一些重叠
    • 当希望成为常量的值其类型不能被常量声明接受时(类/自定义结构体)--静态只读字段
      • 常量的类型只能是普通的值类型,不能是类或者自定义结构体

二、传值 输出 引用 数组 具名 可选参数,扩展方法

2.1 传值参数

2.1.1 值类型 传参

值类型传参 是指将值类型(如 int、struct、enum 等)的变量作为参数传递给方法。值类型传参的核心特点是 传递的是变量值的副本,因此方法内部对参数的修改不会影响原始变量。

  • 副本创建:当值类型变量作为参数传递时,系统会创建一个与原始值相同的副本。
  • 独立作用域:方法内部操作的是副本,原始变量不受影响。
  • 内存分配:副本在方法调用栈上分配独立内存。

值类型传参 流程如图:

  • 代码实例:
csharp 复制代码
namespace ParametersExample
{
    class Program
    {
        static void Main(string[] args)
        {
            int num = 100;
            Student student = new Student();
            student.AddOne(num);

            Console.WriteLine(num);
        }
    }

    class Student
    {
        public void AddOne(int num)
        {
            num ++;
            Console.WriteLine(num);
        }
    }
}
  • 定义一个值类型的变量 num

  • 传值进方法后,方法内的变量 num 会变更

  • 方法外的变量 num 不会随着值参数的变化而变化

  • 调试结果:

2.1.2 引用类型 传参

引用类型传参 是指将引用类型(如 class、array、string、interface 等)的变量作为参数传递给方法。引用类型传参的核心特点是 传递的是对象引用的副本,而非对象本身

  • 传递时创建引用的副本(内存地址的复制),而非对象的副本。
  • 原始引用和副本引用指向同一个对象实例。
  1. 引用类型传参,创建新对象

    重设引用副本:仅影响副本,不影响原始引用。

csharp 复制代码
namespace ParametersExample
{
    class Program
    {
        static void Main(string[] args)
        {
            StudentOne studentOne = new StudentOne();
            studentOne.Id = 100;
            studentOne.Name = "张三";

            SomeMethod(studentOne);

            Console.WriteLine(studentOne.Id);
            //打印对象的 HashCode,以及属性
            Console.WriteLine("{0},{1}", studentOne.GetHashCode(), studentOne.Name);
        }

        static void SomeMethod(StudentOne student)
        {
            student = new StudentOne();
            student.Id = 1;
            studentOne.Name = "张三";

            Console.WriteLine(studentOne.Id);
            //打印对象的 HashCode,以及属性
            Console.WriteLine("{0},{1}", studentOne.GetHashCode(), studentOne.Name);
        }
    }

    class StudentOne
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
}
  • 定义StudentOne 类,属性ID,Name
  • 初始化一个studentOne 对象,属性赋值,将对象传进SomeMethod 方法
  • SomeMethod 方法内会初始化一个新对象 student ,并赋值
  • 打印方法内外变量的值,虽然名称都是张三,但是实例却不是同一个
  1. 引用类型传参,操作对象,不创建新对象

    修改对象属性 / 状态:影响原始对象。

csharp 复制代码
namespace ParametersExample
{
    class Program
    {
        static void Main(string[] args)
        {
            StudentOne studentOne = new StudentOne();
            studentOne.Id = 100;
            studentOne.Name = "张三";

            SomeMethodOne(studentOne);
            Console.WriteLine(studentOne.Id);
            Console.WriteLine("{0},{1}", studentOne.GetHashCode(), studentOne.Name);
        }

        static void SomeMethodOne(StudentOne studentOne)
        {
            studentOne.Id = 2;  // 方法的副作用
            studentOne.Name = "李四";

            Console.WriteLine(studentOne.Id);
            Console.WriteLine("{0},{1}", studentOne.GetHashCode(), studentOne.Name);
        }
    }

    class StudentOne
    {
        public int Id { get; set; }

        public string Name { get; set; }
    }
}
  • SomeMethodOne 方法内操作对象,重新赋值,方法内外的变量会同时变化.
  • 方法内进行更新属性的操作,称为方法的副作用,较少见,需要避免使用

2.2 引用参数

引用参数(Reference Parameters) 允许方法直接操作调用者提供的变量,而非创建参数的副本。通过 ref 关键字声明引用参数,使方法能够修改原始变量的值或重设其引用。

这是一种强大的参数传递机制,适用于需要双向数据交换的场景。

  • 在方法定义和调用时均需显式使用 ref 关键字。
  • 传递变量的内存地址(而非值或引用的副本)。
  • 方法内部对参数的任何修改直接反映到原始变量
  • 实参必须是已初始化的变量,不能是常量或表达式

2.2.1 引用参数-值类型 传参

引用参数(ref)与值类型传参 的组合允许方法直接操作调用者提供的值类型变量,而非创建其副本。

这种方式结合了 ref 关键字的双向修改能力和值类型的内存特性,常用于需要高效修改值类型变量的场景。

csharp 复制代码
namespace ParametersExample
{
    class Program
    {
        static void Main(string[] args)
        {
            int x = 100;
            addNum(ref x);

            Console.WriteLine(x);
        }

        public static void addNum(ref int x)
        {
            x++;
            Console.WriteLine(x);
        }
    }
}

2.2.2 引用参数 - 引用类型 传参

引用参数(ref)与引用类型传参 的组合允许方法直接操作调用者提供的引用类型变量,包括修改对象状态或重设引用本身。

这种方式结合了 ref 关键字的双向修改能力和引用类型的内存特性,常用于需要更灵活控制对象引用的场景。

  1. 引用参数 - 引用类型 , 创建新对象
csharp 复制代码
namespace ParametersExample
{
    class Program
    {
        static void Main(string[] args)
        {
            StudentOne studentOne = new StudentOne() { Id=1,Name="李四"};
            Console.WriteLine("{0},{1}", studentOne.GetHashCode(), studentOne.Name);
            Console.WriteLine("=============================");
            IWantSideEffect(ref studentOne);
            Console.WriteLine("{0},{1}", studentOne.GetHashCode(), studentOne.Name);

        }


        static void IWantSideEffect(ref StudentOne stu)
        {
            stu = new StudentOne()
            {
                Id = 1, Name="张三"
            };
            Console.WriteLine("{0},{1}",stu.GetHashCode(),stu.Name);
        }
    }

    class StudentOne
    {
        public int Id { get; set; }

        public string Name { get; set; }
    }
}
  1. 引用参数 - 引用类型 , 不创建新对象,改变对象值
csharp 复制代码
namespace ParametersExample
{
    class Program
    {
        static void Main(string[] args)
        {
            StudentOne studentOne = new StudentOne() { Name="李四"};
            Console.WriteLine("{0},{1}", studentOne.GetHashCode(), studentOne.Name);
            Console.WriteLine("=============================");
            IWantSideEffect(ref studentOne);
            Console.WriteLine("{0},{1}", studentOne.GetHashCode(), studentOne.Name);
        }

        static void IWantSideEffect(ref StudentOne stu)
        {
            stu.Name = "李四";
            Console.WriteLine("{0},{1}",stu.GetHashCode(),stu.Name);
        }
    }


    class StudentOne
    {
        public string Name { get; set; }
    }
}

2.3 输出参数

输出参数(Output Parameters) 允许方法通过参数返回多个值,而不仅仅依赖于返回值。通过 out 关键字声明输出参数,使方法能够将计算结果赋值给调用者提供的变量。这是一种简洁且类型安全的多返回值解决方案。

  • 在方法定义和调用时均需显式使用 out 关键字。
  • 传递变量的引用(类似 ref),但无需初始化
  • 方法必须在返回前为所有 out 参数赋值
  • out 参数在方法调用后才被视为已初始化。

2.3.1 输出参数-值类型

csharp 复制代码
namespace ParametersExample
{
    class Program
    {
        static void Main(string[] args)
        {
            double y = 0;
            string x = "100";
            DoubleParser doubleParser = new DoubleParser();
            bool b = doubleParser.tryParser(x, out y);
            if (b)
            {
                Console.WriteLine(y+1);
            }
            else
            {
                Console.WriteLine(y);
            }

        }
    }

    class DoubleParser
    {
        public bool tryParser(string x, out double y)
        {
            try
            {
                y = double.Parse(x);
                return true;
            }
            catch (Exception e)
            {
                y = 0;
                return false;
            }

        }
    }
}

2.3.2 输出参数-引用类型

csharp 复制代码
namespace ParametersExample
{
    class Program
    {
        static void Main(string[] args)
        {
            StudentFactory studentFactory = new StudentFactory();

            StudentOne studentOne = new StudentOne();
            bool res = studentFactory.CreateStu("张三", 35, out studentOne);

            if (res)
            {
                Console.WriteLine("{0},{1}", studentOne.Age, studentOne.Name);
            }
        }
    }


    class StudentOne
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }

    class StudentFactory()
    {
        public bool CreateStu(string Name, int Age, out StudentOne student)
        {
            student = null;
            if (string.IsNullOrEmpty(Name))
            {
                return false;
            }
            if (Age > 100)
            {
                return false;
            }

            student = new StudentOne();
            student.Name = Name;
            student.Age = Age;
            return true;
        }
    }
}

2.4 数组参数 (params)

使用 params 关键字允许方法接收任意数量的参数(包括零个),并在方法内部将其视为数组处理。

  • params 类型[] 参数名
  • 必须是形参列表中最后一个,有params 修饰
  • 可传递数组,或直接传递多个参数值
csharp 复制代码
namespace ParametersExample
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] ints = new int[] { 1, 2, 3 };

			//传递数组
            int num = countSum(ints);
			
			//方法的数组参数用params修饰后,传值变简单
            int num2 = countSum(1, 2, 3);

            Console.WriteLine("{0},{1}", num, num2);
        }

		// 使用 params 关键字的方法
        static int countSum(params int[] array)
        {
            int sum = 0;
            foreach (int i in array)
            {
                sum += i;
            }
            return sum;
        }
    }
}
  • string.Split 方法演示:
csharp 复制代码
namespace ParametersExample
{
    class Program
    {
        static void Main(string[] args)
        {
            string aa = "张三, 李四; 王五# 赵六";
            string[] sss = aa.Split(',', ';', '#');
            foreach (var item in sss)
            {
                Console.WriteLine(item);
            }
        }
    }
}

2.5 具名参数

具名参数(Named Arguments) 允许你在调用方法时通过参数名称而不是位置来指定参数值。这使得代码更具可读性,特别是在处理具有多个参数的方法时,还可以跳过可选参数或按任意顺序传递参数。

  • 通过 参数名: 值 的语法指定参数值。
  • 可以不按方法定义的参数顺序传递参数
  • 可以选择性地为可选参数赋值,未指定的参数使用默认值。
  • 参数位置不再受约束
csharp 复制代码
namespace ParametersExample
{
    class Program
    {
        static void Main(string[] args)
        {
        	// 使用具名参数(顺序可任意)
            printInfo(age: 35,name:"张三");
        }
		static void printInfo(string name,int age)
		{
		    Console.WriteLine("{0},{1}",name,age);
		}

    }
}

2.6 可选参数

可选参数是方法定义里能够设定默认值的参数。调用方法时,这些参数可传值也能不传。

  • 定义方法时,通过赋值运算符(=)给参数赋予默认值
  • 可选参数必须放在必选参数的后面
  • 调用方法时,可以不传入可选参数的值,此时会使用默认值;也可以按顺序传值或者通过命名参数传值。
csharp 复制代码
namespace ParamsExample
{
    internal class Program
    {
        static void Main(string[] args)
        {
            showParams();
        }

        static void showParams(string Name="张三",int Age=35)
        {
            Console.WriteLine("{0},{1}",Name,Age);
        }
    }
}

2.7 扩展方法(this参数)

扩展方法

扩展方法(Extension Methods) 允许你向现有类型 "添加" 方法,而无需创建新的派生类型、修改原始类型或使用复杂的装饰器模式。扩展方法使用 this 关键字修饰第一个参数,使其看起来像被扩展类型的实例方法。这是一种强大的语法糖,常用于增强框架类型或第三方库的功能。

  • 语法
    • 必须定义在静态类中。
    • 第一个参数必须使用 this 关键字修饰。
    • 通常为公共静态方法。
  • 调用方式
    • 像实例方法一样调用(无需显式传入第一个参数)。
    • 需要引入扩展方法所在的命名空间。
  • 优先级
    • 实例方法优先于扩展方法。
    • 多个扩展方法冲突时需显式指定类型调用。
csharp 复制代码
namespace ParamsExample
{
    internal class Program
    {
        static void Main(string[] args)
        {
            string str = "";
            Console.WriteLine(str.IsNullOrWhitespace());
        }
    }

	// 静态类:包含扩展方法
    public static class StringExtensions
    {
        //扩展方法:判断字符串是否为空或空白
        public static bool IsNullOrWhitespace(this string str)
        {
            if (string.IsNullOrEmpty(str))
            {
                return true;
            }

            if (str.Trim().Length == 0)
            {
                return true;
            }

            return false;
        }
    }
}

LINQ 方法

LINQ(Language Integrated Query) 提供了一组标准查询方法,用于对各种数据源(如集合、数组、数据库等)进行高效的查询、筛选、投影和聚合操作。

这些方法既可以通过 ** 方法语法(Method Syntax)直接调用,也可以通过查询语法(Query Syntax)** 以类似 SQL 的形式表达。

csharp 复制代码
namespace ParamsExample
{
    internal class Program
    {
        static void Main(string[] args)
        {
            List<int> list = new List<int>() { 11, 19, 20, 30,15, 19 };

            //访问静态方法
			bool x = AllGreaterThanTen(list);
			Console.WriteLine(x);
			
			//筛选大于10的
			bool y = list.All(i => i > 10);
			Console.WriteLine(y);
        }

        public static bool AllGreaterThanTen(List<int> ints)
        {
            foreach (var item in ints)
            {
                if (item > 10)
                {
                    continue;
                }
                else
                {
                    return false;
                }
            }

            return true;
        }
    }
}

2.8 各种参数的使用场景总结

  • 传值参数:参数的默认传递方式
  • 输出参数:用于除返回值外还需要输出的场景
  • 引用参数:用于需要修改实际参数值的场景
  • 数组参数:用于简化方法的调用
  • 具名参数:提高可读性
  • 可选参数:参数拥有默认值
  • 扩展方法(this参数):为目标数据类型"追加"方法
相关推荐
唐青枫16 分钟前
C#.NET BackgroundService 详解
c#·.net
深度混淆17 分钟前
C#,List<T> 与 Vector<T>
开发语言·c#·vector·list·simd
深度混淆2 小时前
C#,Parallel并行多线程计算,使用专门的Concurrent系列数据集
开发语言·c#·多线程·并行处理
心疼你的一切2 小时前
Unity 多人游戏框架学习系列一
学习·游戏·unity·c#·游戏引擎
Chef_Chen3 小时前
从0开始学习R语言--Day47--Nomogram
学习
毕设源码柳学姐5 小时前
计算机毕业设计Java医学生在线学习平台系统 基于 Java 的医学生在线学习平台设计与开发 Java 医学在线教育学习系统的设计与实现
java·学习·课程设计
永日456706 小时前
学习日记-spring-day46-7.11
java·学习·spring
Yhame.6 小时前
【 Cache 写策略学习笔记】
笔记·学习
Blossom.1186 小时前
从“炼丹”到“流水线”——如何用Prompt Engineering把LLM微调成本打下来?
人工智能·python·深度学习·神经网络·学习·机器学习·prompt
枯萎穿心攻击6 小时前
响应式编程入门教程第三节:ReactiveCommand 与 UI 交互
开发语言·ui·unity·架构·c#·游戏引擎·交互