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++); } }
メソッド、コンストラクター メソッド、パラメーター化されたプロパティ (C# インデクサー) のパラメーターにはデフォルト値を指定できます。デリゲート定義の一部であるパラメーターのデフォルト値を指定することもできます。
デフォルト値を持つパラメータは、デフォルト値のないすべてのパラメータの後に配置する必要があります。ただし、例外が 1 つあります。「パラメータ配列」などのパラメータは、すべてのパラメータ (デフォルト値を持つパラメータを含む) の後に配置する必要があり、配列自体にデフォルト値を設定することはできません。
デフォルト値は、コンパイル時に決定できる定数値である必要があります (プリミティブ型、列挙型、および null に設定できる参照型を含む)。値型のパラメーターは、デフォルト値を値型のインスタンスに設定し、そのすべてのフィールドにゼロ値が含まれるようにします。この意味を表現するには、default または new キーワードを使用できます。2 つの構文によって生成される IL コードはまったく同じです。
パラメータ変数の名前を変更しないでください。変更しない場合、実際のパラメータをパラメータ名で渡す呼び出し元はコードも変更する必要があります。
メソッドがモジュールの外部から呼び出される場合、パラメーターのデフォルト値を変更することは潜在的に危険です。通話サイト (通話が行われる場所) では、通話にデフォルト値が埋め込まれます。後でパラメーターのデフォルト値を変更しても、呼び出しサイトを含むコードを再コンパイルしない場合、メソッドを呼び出すときに古いデフォルト値が渡されます。 デフォルト値 0/null をセンチネル値として使用して、デフォルトの動作を示すことを検討してください。例:
//不要这样做: 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"); }
パラメータが ref または out キーワードでマークされている場合、デフォルト値を設定することはできません。
オプションのパラメータまたは名前付きパラメータを使用してメソッドを呼び出す場合は、次の追加のルールと原則にも注意してください:
実際のパラメータは任意の順序で渡すことができますが、ただし、名前付きの実パラメータは次の場所でのみ使用できます。実際のパラメータリストの終わり。
デフォルト値のないパラメータは名前で渡すことができますが、必要な引数はすべて (位置または名前で) 渡す必要があります。
C# では、M(1,,DateTime.Now)
などのカンマ間の実際のパラメーターを省略することはできません。デフォルト値を持つパラメータの場合、実際のパラメータを省略したい場合は、パラメータ名を渡して実際のパラメータを渡します。
パラメータに ref/out が必要な場合、パラメータ名を渡して実際のパラメータを渡すには、次の構文を使用してください:
//方法声明: private static void M(ref int x) { ...} //方法调用: int a = 5; M(x: ref a);
C# が COM コンポーネントを呼び出すとき、それが by である場合参照 実際のパラメータを渡す場合、C# では ref/out を省略することもできるため、コーディングがさらに簡素化されます。ただし、呼び出しが COM コンポーネントではない場合、C# では ref/out キーワードを実際のパラメーターに適用する必要があります。
var を使用してメソッドのパラメータの型を宣言することはできません。
var を使用して型のフィールドを宣言することはできません。
dynamic と var を混同しないでください。 var を使用したローカル変数の宣言は、コンパイラーが式に基づいて特定のデータ型を推測することを必要とする単純化された構文です。 var キーワードはメソッド内でのみローカル変数を宣言できますが、dynamic キーワードはローカル変数、フィールド、パラメーターに適用されます。式を var に変換することはできませんが、 dynamic に変換することはできます。 var で宣言された変数は明示的に初期化する必要がありますが、dynamic で宣言された変数は初期化する必要はありません。
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 のデフォルトでは、すべてのメソッドパラメータが値によって渡されます。
CLR を使用すると、パラメーターを値ではなく参照によって渡すことができます。 C# は、キーワード out または ref を使用してこの機能をサポートします。
CLRはoutとrefを区別せず、どのキーワードが使用されても同じILコードが生成されます。さらに、メタデータは、メソッドの宣言時に out または ref が指定されたかどうかを記録するために使用される 1 ビットを除いて、ほぼまったく同じです。
C# コンパイラーはこれら 2 つのキーワードを異なる方法で処理し、この違いにより、参照されるオブジェクトの初期化をどちらのメソッドが担当するかが決まります。
out を使用してパラメーターをマークするメソッドはパラメーターの値を読み取ることができないため、戻る前にこの値に書き込む必要があります。逆に、メソッドを ref でマークした場合は、メソッドを呼び出す前にパラメータの値を初期化する必要があります。呼び出されたメソッドは、値を読み取ることも、値に を書き込むこともできません。 ref と 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
}
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; }
声明方法的参数类型时,应尽量指定最弱的类型,宁愿要接口也不要基类。例如,如果要写方法来处理一组数据项,最好是用接口(比如 IEnumerable<T>
)声明参数,而不要用强数据类型(比如List<T>
)或者更强的接口类型(比如ICollection<T>
或IList<T>
):
//好:方法使用弱参数类型 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() { }
以上がオプションのパラメータと名前付きパラメータの例の詳細な説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。