參數列的寫法與參數傳遞:
參數列的寫法決定「參數是如何傳的給函式」,也決定參數在函式作用過後會發生的變化。參數列的寫法有:
(1) 一般寫法:
其對應的參數傳遞方式是「傳值」,是將參數的值傳入函式,也就是說函式只利用參數的值去做運算,但不會改變參數本身的值。寫法為:
變數型態一 參數一, 變數型態二 參數二, 變數型態三 參數三…
如:
public double ten_years_ago(int age_) //這就是我們要討論的傳值函式
{ age_ += 10; return age_; }
public Form1() //這個函式是C# 表單用到的函式,在此並不討論
{ InitializeComponent(); }
private void Form1_Load(object sender, EventArgs e) //這個函式也是C# 表單用到的函式,我們的程式碼就寫在裡頭
{
//以下是我們要討論的程式碼,包括傳值函式的用法
int age_of_Wiewei = 20;
double new_age = ten_years_ago(age_of_Wiewei); //傳值函式的用法
textBox1.Text = "new_age=" + new_age.ToString() + ",age_of_Wiewei=" + age_of_Wiewei.ToString() ;
}
執行後,顯示出結果是:new_age=30,age_of_Wiewei=20
表示函式執行過後,原本的變數(就是age_of_Wiewei)並沒有改變。
(2) 傳址寫法:
其對應的參數傳遞方式是「傳址」,是將參數的記憶體位址傳入函式,也就是說函式除了利用參數的值去做運算,也可以改變參數本身的值。寫法為在變數型態前加上關鍵字ref:
ref 變數型態一 參數一, ref 變數型態二 參數二, ref 變數型態三 參數三…
如:
public double ten_years_ago(ref int age_) //這就是我們要討論的傳址函式
{ age_ += 10; return age_; }
public Form1() //這個函式是C# 表單用到的函式,在此並不討論
{ InitializeComponent(); }
private void Form1_Load(object sender, EventArgs e) //這個函式也是C# 表單用到的函式,我們的程式碼就寫在裡頭
{
//以下是我們要討論的程式碼,包括傳址函式的用法
int age_of_Wiewei = 20;
double new_age = ten_years_ago(ref age_of_Wiewei); //傳址函式的用法:也要在變數名稱前加上關鍵字ref
textBox1.Text = "new_age=" + new_age.ToString() + ",age_of_Wiewei=" + age_of_Wiewei.ToString() ;
}
執行後,顯示出結果是:new_age=30,age_of_Wiewei=30
很明顯的,函式執行過後,原本的變數(就是age_of_Wiewei)已經改變。這效果與傳值函式不同!
(3) 不定數目的參數傳遞:
在前面兩種參數列的寫法中,參數的數目都是在定義函式時,就已寫在參數列上。但事實上,在應用時可能會碰到「要輸入的參數之數目無法事先確定、或可以變動」的情況,那就無法在定義函式時決定參數的數目,則參數列的寫法會變成:
params變數型態[] 變數名稱
其中,該變數名稱所代表的變數是一個「變數矩陣」,也擁有一般矩陣的成員及成員函式,其元素的變數型態為變數型態,其元素數目無法事先定義,端看此函式被呼叫到時,使用者要輸入多少元素。
例如:
public double polynomial(double x_,params double[] coe_) //這就是我們要討論的不定變數數目函式
{
double y_=0;
for (int i = 0; i < coe_.Length; i++)
{ y_ += coe_[i]*Math.Pow(x_,i); } //coe_是一個變數矩陣
return y_;
}
public Form1()
{ InitializeComponent(); }
private void Form1_Load(object sender, EventArgs e)
{
textBox1.Text = polynomial(2,2,5,-1,1).ToString();
}
執行後,輸出:16。正是f(x)=2+5*x-1*x2+1*x3這個數學函式在x=2時的值。因為多項式的係數對應到變數矩陣,所以在使用此函式時可輸入任意數目的多項式係數,來計算任意階多項式f(x)在任何x的值,算是很實用的函式。
再舉一個例子:polynomial(3,9,2)可計算出f(x)=9+2*x在x=3的值。
(4) 不定變數型態的參數傳遞(泛型函式):
在前面的寫法中,參數的變數型態都是在定義函式時,就已寫在參數列上。但事實上,在應用時可能會碰到「要輸入的參數之變數型態無法事先確定」的情況,那就無法在定義函式時決定參數的變數型態,我們稱「不定變數型態的參數」為「泛型參數」,稱「使用泛型參數的函式」為「泛型函式」。泛型函式的寫法為:
回傳值的資料形態 函式名稱<變數型態代號一,變數型態代號二…>(變數型態代號一 參數一, 變數型態代號二 參數二…)
如:
public void show_message<T>(T message_) //這就是我們要討論的泛型函式,其中T是變數型態代號
{ textBox1.Text += message_.ToString();}
public Form1()
{ InitializeComponent(); }
private void Form1_Load(object sender, EventArgs e)
{
show_message("I 'm "); //泛型函式的使用方法,與一般函式一樣
show_message(10);
show_message(" years old.");
}
執行後,輸出:I 'm 10 years old.。
(5) 把外部函式當作參數:
把外部函式當作參數的好處是,本函式在執行時可以依情況呼叫不同的外部函式來處理本函式中的其他參數。欲把外部函式當作參數,則這個被當成參數的外部函式應該寫在本函式的參數列中,且應寫成:
Func<外部函式參數型態一, 外部函式參數型態二, 外部函式參數型態三… 外部函式回傳值型態 > 函式參數名
要注意,在本函式的參數列中也要加上:
外部函式參數型態一 參數一, 外部函式參數型態二 參數二, 外部函式參數型態三 參數三…
好讓外部函式能夠取得其要用的參數。
※ 以下用範例來說明:
這個範例,是想寫一個函式,用來求「數學函式在某個範圍內的最大值」。
double get_local_maximun(double x1_, double x2_, double x_bin_width_,
Func<double, double[], double> math_function_,
// 在此,math_function_就是外部函式參數
params double[] func_pars_) // func_pars_雖在本函式參數列中,但實際上是給外部函式所用的參數
{
double max_=0;
for (double x_ = x1_; x_<=x2_; x_+=x_bin_width_)
{
if (x_==x1_)
{
max_=math_function_(x_,func_pars_); //在此可見,func_pars_是給外部函式所用
continue;
}
if (math_function_(x_,func_pars_)>max_)
{ max_=math_function_(x_,func_pars_);}
}
return max_;
}
//以下有四個數學函式,每個都符合Func<double, double[], double>的格式,也就是說每個都可以被當作get_local_maximun函式的外部函式參數math_function_。
double cos(double x_, params double[] par_)
{ return par_[0] * Math.Cos(par_[1] * x_ + par_[2]) + par_[3]; }
double sin(double x_, params double[] par_)
{ return par_[0] * Math.Sin(par_[1] * x_ + par_[2]) + par_[3]; }
double cos_sin(double x_, params double[] par_)
{
double cos = par_[0] * Math.Cos(par_[1] * x_ + par_[2]) + par_[3];
double sin = par_[4] * Math.Cos(par_[5] * x_ + par_[6]) + par_[7];
return cos + sin;
}
double x_square(double x_, params double[] par_)
{ return par_[0] * x_ * x_ + par_[1] * x_ + par_[2]; }
//這裡假設表單中有一個Button名為button1
private void button1_Click(object sender, EventArgs e)
{
textBox1.Text = get_local_maximun(-Math.PI, Math.PI, 0.01,
cos_sin,2, 3, 1, 0,
1, 4, 2, 0).ToString();
}
// 按下button1後顯示:2.8832540555。是f(x)=2*cos(3*x+1)+0+1*sin(4*x+2)+0在-π<=x<=π之間的計算機最大值。
//這裡假設表單中有一個Button名為button2
private void button2_Click(object sender, EventArgs e)
{ textBox1.Text = get_local_maximun(-10, 10, 0.01, x_square, 1, 1, 5).ToString();}
// 按下button2後顯示:114.9999999。而f(x)=1*x2+1*x+5在-10<=x<=10之間的最大值是115。兩者之間的差別應是計算機的誤差。
//這裡假設表單中有一個Button名為button3
private void button3_Click(object sender, EventArgs e)
{ textBox1.Text = get_local_maximun(-10, 10, 0.01, cos, 1, 2, 0.5, 2).ToString();}
// 按下button3後顯示:3。正是f(x)=1*cos(2*x+0.5)+2在-10<=x<=10之間的最大值。
(6) 利用參數名稱直接指定參數值:
這種方法可以不照順序直接指定某個參數值。適用於函式中參數極多、且並非每個都需要指定的時候。語法為:函式名稱(參數名:參數值);
範例如:
public int A(int a=0, int b=0, int c=0)
{ return a + b + c; }
int tt = A(b: 10, c:3); // 利用參數名稱,直接指定b和c的值
richTextBox1.Text += tt.ToString();
執行後顯示:
13
留言列表