C# メソッドのパラメータ
値パラメータ
値パラメータは、最も一般的に使用されるパラメータです。
宣言時の仮パラメータは不带任何修饰符
値パラメータ(仮パラメータ)です。value パラメーターは、メソッド呼び出し時に指定された実パラメーター (実パラメーター)から初期化値が取得されるローカル変数に対応します。メソッド内部の仮パラメータを変更しても、メソッド外部の実際のパラメータには影響しません。形参是方法内的一个局部变量,方法调用时形参拷贝了传入的实参的值,此后,形参和实参再无半分瓜葛。
class Program
{
static void Main(string[] args)
{
int y = 100;
Program.PrintAdd(y); // 输出 101
Console.WriteLine(y); // 输出100
}
static void PrintAdd(int x)
{
x = x + 1;
Console.WriteLine(x);
}
}
値パラメータは引用数据类型
値パラメータが参照データ型の場合、仮パラメータは実パラメータの参照をコピーしますが、本質的には実パラメータと仮パラメータは依然として 2 つの異なる変数です。違いは次のとおりです。
基本数据类型
格納されるのは基本データの値そのもので、例えばint型には整数が格納されます。引用数据类型
格納されるのは参照先のオブジェクトのアドレスで、例えばクラスオブジェクトの変数にはオブジェクトのアドレスが格納されます。
混同しやすいことの 1 つは、
オブジェクトがメソッドに渡されるとき、そのフィールドがメソッド内のオブジェクトを通じて変更された後、メソッド外のオブジェクトの対応するフィールドが変更されることです。現時点では値パラメータではありません。実際には、これは依然として値パラメータであり、仮パラメータは実際のパラメータの値をコピーしますが、この値は参照データ型のアドレスです。コピー後は仮引数と実引数に格納されている値は同じアドレスとなり、このときメソッド内の仮引数を通じてアドレスにアクセスできるようになります。形参.字段
このとき、あるフィールド(フィールドの型は基本データ型でも参照データ型でもよい)の値が変更されると、仮引数が指すアドレスに格納されているオブジェクトのフィールドが変更され、仮引数が変更されます。仮パラメータに保存されるのは参照先オブジェクトのアドレスのみであるため、パラメータ自体は変更されません。唯一の形参 = 新对象
方法は、仮パラメータ自体を変更することです。したがって、値パラメータの定義に準拠したままに形参 = 新对象
なります。实参 == 新对象
class Student
{
public string name;
public int age;
}
class Program
{
static void Main(string[] args)
{
Student stu = new Student();
stu.name = "yy";
stu.age = 100;
Program.Test(stu);
// 到这里stu的字段的值分别是:
name = "xx";
age = 100;
// 新旧hash code 是不一样的
Console.WriteLine("hash code: {0}", stu.GetHashCode());
}
static void Test(Student stu)
{
// 通过形参stu访问了一个Student对象的字段name,并修改之,此修改外部能感知
stu.name = "xx";
stu = new Student(); // 形参新赋值了一个新对象,外部实参依旧是旧的对象
// 这两次赋值是对新对象的字段的赋值,并不会对
// 旧对象的字段造成影响
stu.name = "bb";
stu.age = 20;
Console.WriteLine("hash code: {0}", stu.GetHashCode());
}
}
参照パラメータ
修飾子を使用して宣言された仮パラメータref
は です引用参数
。値パラメーターとは異なり、参照パラメーターは新しい保管場所を作成しません。言い換えれば、参照パラメータの実パラメータと仮パラメータは同じ格納場所を参照します。
class Program
{
static void Main(string[] args)
{
double a = 20;
Add(ref a); // a == 21
Console.WriteLine(a); // a == 21
}
static void Add(ref int a)
{
a = a + 1;
Console.WriteLine(a);
}
}
出力パラメータ
修飾子を使用して宣言された仮パラメータout
は です输出参数
。参照パラメータと同様に、出力パラメータは新しい格納場所を作成しません。出力パラメータの仮パラメータの格納場所は、実際のパラメータの格納場所とまったく同じです。つまり、出力パラメータの合計はまったく同じ変数形参
です实参
。
出力パラメーターの設計では、メソッド内から値を取得します。出力パラメータの初期値はメソッド内で上書きされるため、初期値には意味がなく、初期値を割り当てる必要はありません。出力パラメータは、追加の関数の戻り値として理解できます。
class Program
{
static void Main(string[] args)
{
double result;
// 调用时也显式地写上out,让人一看就知道是输出参数
bool b = TryAdd("1", "100", out result);
if (b)
Console.WriteLine("{0} + {1} = {2}", "1", "100", result);
}
// a和b能被解析成double并相加成功的话才返回true
static bool TryAdd(string a, string b, out double res)
{
try
{
res = double.Parse(a) + double.Parse(b);
return true;
} catch {
res = 0;
return false;
}
}
}
参照パラメータ VS 出力パラメータ
キーワードout
とキーワードref
は等效的
、つまり、どのキーワードが使用されるかに関係なく、同じメタデータと IL コードが生成されます。
ただし、C# コンパイラは 2 つを異なる方法で処理します。これら 2 つのキーワードの違いは です谁负责初始化
。
out
: 呼び出し元はメソッドを呼び出す前にオブジェクトを初期化したくないため、呼び出されたメソッドはオブジェクトの値を読み取ることができず、呼び出されたメソッドは戻る前にオブジェクトに値を割り当てる必要があります。ref
: 呼び出し元は、メソッドを呼び出す前に、まずパラメータの値を初期化する必要があります。呼び出されたメソッドは、パラメータを読み取ることも、パラメータに値を割り当てることもできます。
配列パラメータ
修飾子を使用して宣言された仮パラメータparams
は です数组参数
。
// 普通的数组参数声明
void Method(int[] arr){
...}
// 调用时需要先创建一个数组,然后再传入
int[] array = new int[]{
1, 2, 3};
XXX.Method(array);
// 如果加上修饰符params就可以直接在调用方法时顺序输入值
// 声明方法
void Method(params int[] arr){
...}
// 调用
XXX.Method(1, 2, 3);
// 可以直接输入而无需创建数组
注: メソッドのパラメータ リストには 0 または 1 つのparams
パラメータのみを含めることができ、params
パラメータはパラメータ リストの最後にのみ配置できます。
オプションのパラメータ
これは、メソッドを宣言するときにパラメータのデフォルト値を提供するものです可选参数
。パラメータにはデフォルト値があるため、 になります可选
。
...
// 声明一个参数有默认值的方法
public void Method(string name = "李四", int age = 20){
...}
...
// 因为Method方法有默认值,所以参数是可选的
// 不传入实参,形参默认使用的是默认值
XXX.Method(); // name = "李四", age = 20
名前付きパラメータの呼び出し
名前付きパラメータを使用した呼び出しは、コードを書く習慣とみなすことができます。一般的に、関数を呼び出すときは、パラメータの値 (または変数の名前) を入力するだけです。たとえば、これは匿名呼び出しとみなされますXXX.Method(100, "你好");
。 。名前付き呼び出しでは、パラメーターの名前を明示的に記述する必要があります。例えば:
...
// 方法
public void Method(int id, string name){
...}
...
// 匿名调用
XXX.Method(1, "张三");
// 具名调用
XXX.Method(id:1, name:"张三");
// 具名调用可以忽略参数列表的顺序
XXX.Method(name:"张三", id:1); // 这样写等同于上面
このパラメータ(拡張メソッド)
拡張メソッド (このパラメーターとも呼ばれます) は、ソース コードを変更できないがメソッドを追加する必要があるクラスにメソッドを追加できます。
メソッドは public static に変更する必要があります。
次の例では、ToInt メソッドを文字列クラスに追加します。
class Pragram
{
static void Main(string[] args)
{
string a = "100";
// 因为input参数就是this,会
// 自动传入a,所以不用显式传入
// 参数
int b = a.ToInt();
}
}
// 声明一个静态类,这是string的扩展类
static class StringExtension
{
// 对string扩展了ToInt方法
// 该方法可以将字符串转成int
// this修饰的必须是第一个参数
public static int ToInt(this string input)
{
int res;
try
{
res = int.Parse(input);
}
catch
{
res = -1;
}
return res;
}
}