• 【C# Programming】编程入门:方法和参数


    一、方法

    1、方法的定义

            由一系列以执行特定的操作或计算结果语句组成。方法总是和类关联,类型将相关的方法分为一组。

    • 方法名称  
    • 形参和实参(parameter & argument)
    • 返回值

    2、命名空间

            一种分类机制,用于组合功能相关的所有类型。命名空间是分级的,级数可以是任意。 命名空间层级一般从公司名开始,然后是产品名,最后是功能领域,例如:

    • Microsoft.Win32.Networking

            主要用于按照功能领域组织,以便更容易查找和理解它们。除此之外,命名空间还有助于防止类型名称发生冲突.

    3、作用域

    • 可以通过非限定名称引用到的区域  
    • 对于某个类型中一个方法的调用,如果这个方法在类型中声明,那么对该方法的调用不需要使用类型限定符; 类似的,一个类型对声明了它的整个命名空间也都在作用域内。

    二、表达式

    1、表达式主题成员

            表达式主体成员提供了一种更简洁、更可读的成员实现

    MemberSupported as of...
    MethodC# 6
    ConstructorC# 7
    FinalizerC# 7
    Property GetC# 6
    Property SetC# 7
    IndexerC# 7

            语法:member => expression

    2、表达式主体方法

            表达式主体方法使用箭头操作符 (=>) 将单个表达式分配到一个属性或方法来替代语句体 ,如果方法有返回值, 该表达式返回值必须与方法返回类型相同;如果方法无返回值,则表达式执行一系列操作。

    1. public class Person
    2. {
    3. public Person(string firstName, string lastName)
    4. {
    5. fname = firstName;
    6. lname = lastName;
    7. }
    8. private string fname;
    9. private string lname;
    10. public override string ToString() => $"{fname} {lname}".Trim();
    11. public void DisplayName() => Console.WriteLine(ToString());
    12. }

    三、方法声明

            C# 不支持全局方法,所有方法都必须在某个类型中。

    1. public class Program
    2. {
    3. public static void ChapterMain()
    4. {
    5. string firstName, lastName, fullName, initials;
    6. System.Console.WriteLine("Hey you!");
    7. firstName = GetUserInput("Enter your first name: ");
    8. lastName = GetUserInput("Enter your last name: ");
    9. fullName = GetFullName(firstName, lastName);
    10. initials = GetInitials(firstName, lastName);
    11. DisplayGreeting(fullName, initials);
    12. }
    13. static string GetUserInput(string prompt)
    14. {
    15. System.Console.Write(prompt);
    16. return System.Console.ReadLine();
    17. }
    18. static string GetFullName( string firstName, string lastName) => $"{ firstName } { lastName }";
    19. static void DisplayGreeting(string fullName, string initials)
    20. {
    21. System.Console.WriteLine($"Hello { fullName }! Your initials are { initials }");
    22. }
    23. static string GetInitials(string firstName, string lastName)
    24. {
    25. return $"{ firstName[0] }. { lastName[0] }.";
    26. }
    27. }

    四、Main() 的返回值和参数

            C# 支持在执行程序时提供命令行参数,并运行从Main() 方法返回状态标识符,当需要从非Main()方法中访问命令行参数时, 可用System.Environment.GetcommandLineArgs() 方法:

    1. public static int Main(string[] args)
    2. {
    3. int result;
    4. string targetFileName, string url;
    5. switch(args.Length)
    6. {
    7. default:
    8. Console.WriteLine("ERROR: You must specify the "+ "URL and the file name"); // Exactly two arguments must be specified; give an error.
    9. targetFileName = null;
    10. url = null;
    11. break;
    12. case 2:
    13. url = args[0];
    14. targetFileName = args[1];
    15. break;
    16. }
    17. if(targetFileName != null && url != null)
    18. {
    19. using (HttpClient httpClient = new HttpClient())
    20. using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, url))
    21. using (HttpResponseMessage message = httpClient.SendAsync(request).Result)
    22. using (Stream contentStream = message.Content.ReadAsStreamAsync().Result)
    23. using (FileStream fileStream = new FileStream(targetFileName, FileMode.Create, FileAccess.Write, FileShare.None))
    24. {
    25. contentStream.CopyToAsync(fileStream);
    26. }
    27. return 0;
    28. }
    29. Console.WriteLine("Usage: Downloader.exe ");
    30. return 1;
    31. }

    五、方法的参数

    1、值参数

    C# 中,参数传递默认是值传递的, 也就是说,参数表达式的值会复制到目标参数中。

    • 对于值类型参数,方法获得是值的副本,所以方法内无法改变实参的值  
    • 对于引用类型参数,方法获得的是引用(地址)的副本,方法可以改变引用对象的值
    1. public static void ChapterMain()
    2. {
    3. string fullName;
    4. string driveLetter = "C:";
    5. string folderPath = "Data";
    6. string fileName = "index.html";
    7. fullName = Combine(driveLetter, folderPath, fileName);
    8. Console.WriteLine(fullName);
    9. }
    10. static string Combine(string driveLetter, string folderPath, string fileName)
    11. {
    12. string path;
    13. path = string.Format("{1}{0}{2}{0}{3}", System.IO.Path.DirectorySeparatorChar, driveLetter, folderPath, fileName);
    14. return path;
    15. }

    2、引用参数(ref)

    • ref 关键字表明参数是通过引用传递而不是值传递。无论实参是值类型还是引用类型,都可以通过引用传递
    • 如果方法定义使用了ref 关键字,调用方法时实参前必须显式使用ref 限定
    • 使用ref 限定的实参必须在调用前初始化  
    • 对于值类型参数,引用传递使得方法 可以改变实参的值
    1. class RefExample
    2. {
    3. static void Method(ref int i)
    4. {
    5. i = i + 44;
    6. }
    7. static void Main()
    8. {
    9. int val = 1;
    10. Method(ref val);
    11. Console.WriteLine(val); // Output: 45
    12. }
    13. }
    • 对于引用类型参数,引用传递使得方法不仅可以改变引用对象的值,也可以更换引用参数引用的对象
    1. class RefExample2
    2. {
    3. static void Main()
    4. {
    5. Product item = new Product("Fasteners", 54321);// Declare an instance of Product and display its initial values.
    6. System.Console.WriteLine("Original values in Main. Name: {0}, ID: {1}\n", item.ItemName, item.ItemID);
    7. ChangeByReference(ref item); // Pass the product instance to ChangeByReference.
    8. System.Console.WriteLine("Back in Main. Name: {0}, ID: {1}\n", item.ItemName, item.ItemID);
    9. }
    10. static void ChangeByReference(ref Product itemRef)
    11. {
    12. // Change the address that is stored in the itemRef parameter.
    13. itemRef = new Product("Stapler", 99999);
    14. itemRef.ItemID = 12345;
    15. }
    16. }
    17. class Product
    18. {
    19. public Product(string name, int newID)
    20. {
    21. ItemName = name;
    22. ItemID = newID;
    23. }
    24. public string ItemName { get; set; }
    25. public int ItemID { get; set; }
    26. }

    3、out参数

    1. 类似ref,out也表明参数是通过引用传递而不是值传递; 方法定义时形参指定了out,调用时实参也必须使用out 显式指定 
    2. out 和ref 区别如下: 
      1. 使用out限定的实参不必在调用前初始化
      2. 方法在返回前必须对所有out参数赋值,编译器会检查所有返回路径确保所有的out 参数被赋值
    3. out 常用于需要从方法返回多个值的场合
    1. class OutReturnExample
    2. {
    3. static void Method(out int i, out string s1, out string s2)
    4. {
    5. i = 44;
    6. s1 = "I've been returned";
    7. s2 = null;
    8. }
    9. static void Main()
    10. {
    11. int value;
    12. string str1, str2;
    13. Method(out value, out str1, out str2);
    14. }
    15. }

    4、参数数组(param)

    通过在方法参数前显式指定 param,   C# 允许在调用方法时提供可变数量参数  

    • 参数数组不一定是方法的唯一参数,但必须是方法最后一个参数  
    • 实参的类型必须兼容与参数数组中元素的类型  
    • 调用者既可以传递以逗号分隔的参数,也可以显式使用数组  
    • 调用者可以指定和参数数组对应的零个实参
    1. public static void ChapterMain()
    2. {
    3. string fullName;
    4. fullName = Combine(Directory.GetCurrentDirectory(), "bin", "config", "index.html"); // Call Combine() with four parameters
    5. Console.WriteLine(fullName);
    6. fullName = Combine(Directory.GetParent(Directory.GetCurrentDirectory()).FullName, "Temp", "index.html"); // Call Combine() with only three parameters
    7. Console.WriteLine(fullName);
    8. fullName = Combine( new string[] {$"C:{Path.DirectorySeparatorChar}", "Data", "HomeDir", "index.html" }); // Call Combine() with an array
    9. Console.WriteLine(fullName);
    10. }
    11. static string Combine(params string[] paths)
    12. {
    13. string result = string.Empty;
    14. foreach (string path in paths)
    15. result = System.IO.Path.Combine(result, path);
    16. return result;
    17. }

    5、命名参数(named argument)

    调用者显式地为一个参数赋值

    • 调用者能以任何次序指定参数  
    • 当命名参数和常规方法混合使用时,命名参数必须在所有常规参数传递之后
    1. static void Main(string[] args)
    2. {
    3. PrintOrderDetails("Gift Shop", 31, "Red Mug"); // The method can be called in the normal way, by using positional arguments.
    4.     // Named arguments can be supplied for the parameters in any order.
    5.     PrintOrderDetails(orderNum: 31, productName: "Red Mug", sellerName: "Gift Shop");
    6.     PrintOrderDetails(productName: "Red Mug", sellerName: "Gift Shop", orderNum: 31);
    7.     // Named arguments mixed with positional arguments are valid as long as they are used in their correct position.
    8.     PrintOrderDetails("Gift Shop", 31, productName: "Red Mug");
    9.     // However, mixed arguments are invalid if used out-of-order. The following statements will cause a compiler error.
    10.     // PrintOrderDetails(productName: "Red Mug", 31, "Gift Shop");
    11.     // PrintOrderDetails(31, sellerName: "Gift Shop", "Red Mug");
    12.     // PrintOrderDetails(31, "Red Mug", sellerName: "Gift Shop");
    13. }
    14. static void PrintOrderDetails(string sellerName, int orderNum, string productName)
    15. {
    16. if (string.IsNullOrWhiteSpace(sellerName))
    17. throw new ArgumentException(message: "Seller name cannot be null or empty.", paramName: nameof(sellerName));
    18.     Console.WriteLine($"Seller: {sellerName}, Order #: {orderNum}, Product: {productName}");
    19. }

    6、可选参数(optional arguments)

    1. 方法定义时可指定参数是否可选。方法调用时必须提供所有非可选参数,允许忽略可选参数。
    2. 每个可选参数都必须有缺省值,缺省值为以下类型之一
      1. 常量表达式  
      2. 形如 new valType 的表达式; valType 为值类型,比如:struct 和 enum
      3. 形如 default(valType) 的表达式; valType为值类型
    3. 可选参数类型必须在所有非可选参数之后定义。
    4. 方法调用时,如果为某一可选参数提供了值,该参数之前的所有可选参数都必须指定值;但是使用命名参数可以忽略该规则

    可选参数例子:

    1. static void Main(string[] args)
    2. {
    3. // Instance anExample does not send an argument for the constructor‘s optional parameter.
    4.     ExampleClass anExample = new ExampleClass();
    5.     anExample.ExampleMethod(1, "One", 1);
    6.     anExample.ExampleMethod(2, "Two");
    7.     anExample.ExampleMethod(3);
    8.     // Instance anotherExample sends an argument for the constructor‘s optional parameter.
    9.     ExampleClass anotherExample = new ExampleClass("Provided name");
    10.     anotherExample.ExampleMethod(1, "One", 1);
    11.     anotherExample.ExampleMethod(2, "Two");
    12.     anotherExample.ExampleMethod(3);
    13.                         
    14.     // You cannot leave a gap in the provided arguments.
    15.     //anExample.ExampleMethod(3, ,4);
    16.     //anExample.ExampleMethod(3, 4);
    17.     // You can use a named parameter to make the previous statement work.
    18.     anExample.ExampleMethod(3, optionalint: 4);
    19. }
    20. class ExampleClass
    21. {
    22. private string _name;
    23.     public ExampleClass(string name = "Default name")
    24.     {
    25.     _name = name;
    26.     }
    27.     public void ExampleMethod(int required, string optionalstr = "default string", int optionalint = 10)
    28.     {
    29.     Console.WriteLine("{0}: {1}, {2}, and {3}.", _name, required, optionalstr, optionalint);
    30.     }
    31. }

    六、方法重载

    类似于C++, C# 也支持方法重载。C# 根据参数类型和参数个数选择最匹配的方法

    命名参数和可选参数影响重载规则

    • 如果方法每个参数或者是可选的,或按名称或位置恰好对一个实参,且该实参可转换为参数的类型,则方法成为候选项。
    • 如果找到多个候选项,则首选转换的重载规则应用于显式指定的实参。忽略调用者没有提供实参的所有可选参数 。
    • 如果两个候选项不相上下,优先选择没有使用缺省值的可选参数的候选项。 这是重载决策中优先选择参数较少的候选项规则产生 的结果。
  • 相关阅读:
    一个开源的音频分离深度学习项目
    PID算法及其实现
    11 抽象向量空间
    计算机毕业设计ssm河北经贸大学心理测试辅导平台6d6qg系统+程序+源码+lw+远程部署
    LLMs AWS Sagemaker JumpStart
    java图片转成base64传给前端
    Redis的安装
    进程、线程、处理机调度
    JAVA主要API
    【算法练习Day12】树的递归遍历&&非递归遍历
  • 原文地址:https://blog.csdn.net/weixin_44906102/article/details/132638468