Home > Article > Backend Development > Detailed explanation of optional parameters and named parameter examples
class Program { private static int s_n = 0; private static void M(int x = 9, string s = "A", DateTime dt = default(DateTime), Guid guid = new Guid()) { Console.WriteLine("x={0},s={1},dt={2},guid={3}", x, s, dt, guid); } public static void Main() { //1.等同于M(9,"A",default(DateTime),new Guid()); M(); //2.等同于M(8,"X",default(DateTime),new Guid()); M(8, "X"); //3.等同于M(5,"A",DateTime.Now,Guid.NewGuid()); M(5, guid: Guid.NewGuid(), dt: DateTime.Now); //4.等同于M(0,"1",default(DateTime),new Guid()); M(s_n++, s_n++.ToString()); //5.等同于以下两行代码: //string t1="2";int t2=3; //M(t2,t1,default(DateTime),new Guid()); M(s: (s_n++).ToString(), x: s_n++); } }
can be methods, constructor methods and parameterized properties (C# indexer ) parameters specify default values. You can also specify default values for parameters that are part of the delegate definition.
Parameters with default values must be placed after all parameters without default values. But there is one exception: parameters such as "parameter array" must be placed after all parameters (including those with default values), and the array itself cannot have a default value.
The default value must be a constant value that can be determined at compile time (including primitive types, enumeration types, and any reference type that can be set to null). A parameter of a value type sets the default value to an instance of the value type and causes all its fields to contain zero values. You can use the default or new keyword to express this meaning. The IL code generated by the two syntaxes is exactly the same.
Do not rename parameter variables, otherwise any caller that passes actual parameters by parameter name must also modify their code.
#If the method is called from outside the module, changing the default value of the parameter is potentially dangerous. The call site (where the call is made) embeds default values in its calls. If you later change the parameter's default value, but do not recompile the code containing the call site, it will pass the old default value when it calls your method. Consider using the default value 0/null as a sentinel value to indicate the default behavior. Example:
//不要这样做: private static string MakePath(string filename = "Untitled") { return string.Format(@"c\{0}.txt", filename); } //而要这样做: private static string MakePath(string filename = null) { return string.Format(@"C:\{0}.txt", filename ?? "Untitled"); }
If the parameter is marked with the ref or out keyword, the default value cannot be set.
When calling a method with optional or named parameters, be aware of the following additional rules and principles:
The actual parameters can be in any order Passed, but named arguments can only appear at the end of the argument list .
Parameters without default values can be passed by name, but all required arguments must be passed (either by position or by name).
C# does not allow omitting actual parameters between commas, such as M(1,,DateTime.Now)
. For parameters with default values, if you want to omit their actual parameters, just pass the actual parameters by passing the parameter name.
If the parameter requires ref/out, in order to pass the actual parameter by passing the parameter name, please use the following syntax:
//方法声明: private static void M(ref int x) { ...} //方法调用: int a = 5; M(x: ref a);
C# When calling a COM component, if actual parameters are passed by reference, C# also allows ref/out to be omitted to further simplify coding. But if the call is not a COM component, C# requires that the ref/out keyword must be applied to the actual parameters.
Cannot use var to declare method parameters type.
You cannot use var to declare fields in a type.
Don't confuse dynamic with var. Declaring local variables with var is just a simplified syntax that requires the compiler to infer the specific data type based on the expression. The var keyword can only declare local variables inside a method, while the dynamic keyword applies to local variables, fields and parameters. The expression cannot be converted to var, but it can be converted to dynamic. Variables declared with var must be explicitly initialized, but variables declared with dynamic need not be initialized.
private static void ImplicitlyTypedLocalVariables() { var name = "Jeff"; ShowVariableType(name); //显示:System.String //var n=null; //错误,不能将null赋给隐式类型的局部变量 var x = (String)null; //可以这样写,但意义不大 ShowVariableType(x); //显示:System.String var numbers = new int[] { 1, 2, 3, 4 }; ShowVariableType(numbers); //显示:System.Int32[] //复杂类型能少打一些字 var collection = new Dictionary<String, Single>() { { "Grant", 4.0f } }; //显示:System.Collections.Generic.Dictionary`2[System.String,System.Single] ShowVariableType(collection); foreach (var item in collection) { //显示:System.Collections.Generic.KeyValuePair`2[System.String,System.Single] ShowVariableType(item); } } private static void ShowVariableType<T>(T t) { Console.WriteLine(typeof(T)); }
CLR defaults to all method parameters passing by value.
The CLR allows parameters to be passed by reference rather than by value. C# supports this functionality using the keywords out or ref.
The CLR does not distinguish between out and ref, and the same IL code will be generated regardless of which keyword is used. In addition, the metadata is almost identical, except for one bit, which is used to record whether out or ref is specified when declaring the method.
The C# compiler treats these two keywords differently, and this difference determines which method is responsible for initializing the referenced object.
The method using out to mark the parameter cannot read the value of the parameter, and must write to this value before returning. In contrast, if a method is marked with ref, the value of the parameter must be initialized before calling the method. The called method can read the value and/or write to the value;
Use out
public static void Main() { int x; //x没有初始化 GetVal(out x); //x不必初始化 Console.WriteLine(x); //显示“10” } private static void GetVal(out int v) { v = 10; //该方法必须初始化v }
Use ref
public static void Main() { int x = 5; //x已经初始化 GetVal(ref x); //x必须初始化 Console.WriteLine(x); //显示“15” } private static void GetVal(ref int v) { v += 10; //该方法可使用v的已初始化的值 }
Cannot be defined only on ref and out Different overloading methods.
The variable passed to the method by reference must be of the same type as the type declared in the method signature.
public static void Main() { string s1 = "Jeffrey"; string s2 = "Richter"; //错误!错误!错误! //Swap(ref s1, ref s2); //以传引用的方式传递的变量, //必须和方法预期的匹配 object o1 = s1, o2 = s2; Swap(ref o1,ref o2); //完事后再将object转型为string s1 = (string)o1; s2 = (string)o2; Console.WriteLine(s1); //显示“Richter” Console.WriteLine(s2); //显示“Jeffrey” } private static void Swap(ref object a, ref object b) { object t = b; b = a; a = t; }
Generics can be used to modify the above method
public static void Main() { string s1 = "Jeffrey"; string s2 = "Richter"; Swap(ref s1, ref s2); Console.WriteLine(s1); //显示“Richter” Console.WriteLine(s2); //显示“Jeffrey” } private static void Swap<T>(ref T a, ref T b) { T t = b; b = a; a = t; }
params 只能应用于方法签名中的最后一个参数。
这个参数只能标识一维数组(任意类型)。
可为这个参数传递 null 值,或传递对包含零个元素的一个数组的引用。
调用参数数量可变的方法对性能有所影响(除非显式传递null)。要减少对性能的影响,可考虑定义几个没有使用 params 关键字的重载版本,如System.String
类的Concat方法。
public static void Main() { Console.WriteLine(Add(new int[] { 1, 2, 3, 4, 5 }));//显示“15” //或 Console.WriteLine(Add(1, 2, 3, 4, 5)); //显示“15” //以下两行都显示“0” Console.WriteLine(Add()); //向Add传递 new int[0] Console.WriteLine(Add(null)); //向Add传递 null :更高效(因为不会分配数组) } private static int Add(params int[] values) { // 注意:如果愿意,可将values数组传给其他方法 int sum = 0; if (values != null) { for (int x = 0; x < values.Length; x++) sum += values[x]; } return sum; }
声明方法的参数类型时,应尽量指定最弱的类型,宁愿要接口也不要基类。例如,如果要写方法来处理一组数据项,最好是用接口(比如 IEnumerable8742468051c85b06f0a0af9e3e506b5c
)声明参数,而不要用强数据类型(比如List8742468051c85b06f0a0af9e3e506b5c
)或者更强的接口类型(比如ICollection8742468051c85b06f0a0af9e3e506b5c
或IList8742468051c85b06f0a0af9e3e506b5c
):
//好:方法使用弱参数类型 public void ManipulateItems<T>(IEnumerable<T> collection){} //不好:方法使用强参数类型 public void ManipulateItems<T>(List<T> collection) { }
相反,一般最好是将方法的返回类型声明为最强的类型(防止受限于特定类型)。例如,方法最好返回FileStream而不是Stream对象:
//好:方法使用强返回类 public FileStream OpenFile() { } //不好:方法使用弱返回类 public Stream OpenFile() { }
如果想保持一定的灵活性,在将来更改方法返回的东西,请选择一个较弱的返回类型。
//灵活:方法使用较弱的返回类型 public IList<string> GetStringCollection() { } //不灵活:方法使用较强的返回类型 public List<string> GetStringCollection() { }
The above is the detailed content of Detailed explanation of optional parameters and named parameter examples. For more information, please follow other related articles on the PHP Chinese website!