原文地址:http://www.dingos.cn/index.php?topic=865.0
【方法】
发往某个对象的消息对应于一个方法调用。作为对消息的响应,对象将执行一个类似于过程体的方法。方法是包含在类中的函数。
方法用来表示类和对象的行为,当需要类的对象做一件事情的时候,需要在类中添加方法。
方法是包含一系列语句的代码块。在 C# 中,每个执行指令都是在方法的上下文中执行的。
方法是通过指定访问级别、返回值、方法名称和任何方法参数在类或结构中声明的。这些部分统称为方法的“签名”。 方法参数括在括号中,并用逗号隔开。空括号表示方法不需要参数。
方法定义:
在对象上调用方法类似于访问字段。在对象名称之后,依次添加句点、方法名称和括号。参数在括号内列出,并用逗号隔开。
调用方法的步骤:
发往某个对象的消息对应于一个方法调用。作为对消息的响应,对象将执行一个类似于过程体的方法。方法是包含在类中的函数。
方法用来表示类和对象的行为,当需要类的对象做一件事情的时候,需要在类中添加方法。
方法是包含一系列语句的代码块。在 C# 中,每个执行指令都是在方法的上下文中执行的。
方法是通过指定访问级别、返回值、方法名称和任何方法参数在类或结构中声明的。这些部分统称为方法的“签名”。 方法参数括在括号中,并用逗号隔开。空括号表示方法不需要参数。
方法定义:
访问修饰符 返回类型 方法名(参数列表){
// 方法体
}
}
class Motorcycle{
public void StartEngine() { }
public void AddGas(int gallons) { }
public int Drive(int miles, int speed) { return 0; }
}
public void AddGas(int gallons) { }
public int Drive(int miles, int speed) { return 0; }
}
在对象上调用方法类似于访问字段。在对象名称之后,依次添加句点、方法名称和括号。参数在括号内列出,并用逗号隔开。
调用方法的步骤:
- 将被调用方法的类实例化为一个对象。
- 对象调用它的成员方法。
Motorcycle moto = new Motorcycle();
moto.StartEngine();
moto.AddGas(15);
moto.Drive(5, 20);
moto.AddGas(15);
moto.Drive(5, 20);
【方法的参数】
如果要将参数传递给方法,只需在调用方法时在括号内提供这些参数即可。对于被调用的方法,传入的变量称为“参数”。
方法所接收的参数也是在一组括号中提供的,但必须指定每个参数的类型和名称。该名称不必与参数相同。
注意:
默认情况下,将“值类型”传递给方法时,传递的是副本而不是对象本身。由于它们是副本,因此对参数所做的更改都不会在调用方法内反映出来。之所以叫做值类型,是因为传递的是对象的副本而不是对象本身。传递的是值,而不是同一个对象。
将“引用类型”传递给方法是,是按引用传递的。将基于引用类型的对象传递到方法时,不会创建对象的副本。而是创建并传递对用作方法参数的对象的引用。因此,通过此引用所进行的更改将反映在调用方法中。引用类型是通过使用 class 关键字创建的。
如果要将参数传递给方法,只需在调用方法时在括号内提供这些参数即可。对于被调用的方法,传入的变量称为“参数”。
方法所接收的参数也是在一组括号中提供的,但必须指定每个参数的类型和名称。该名称不必与参数相同。
public static void PassesInteger(){
int fortyFour = 44;
TakesInteger(fortyFour);
}
static void TakesInteger(int i){
i = 33;
}
TakesInteger(fortyFour);
}
static void TakesInteger(int i){
i = 33;
}
注意:
默认情况下,将“值类型”传递给方法时,传递的是副本而不是对象本身。由于它们是副本,因此对参数所做的更改都不会在调用方法内反映出来。之所以叫做值类型,是因为传递的是对象的副本而不是对象本身。传递的是值,而不是同一个对象。
将“引用类型”传递给方法是,是按引用传递的。将基于引用类型的对象传递到方法时,不会创建对象的副本。而是创建并传递对用作方法参数的对象的引用。因此,通过此引用所进行的更改将反映在调用方法中。引用类型是通过使用 class 关键字创建的。
public class SampleRefType{
public int value;
}
public static void TestRefType(){
SampleRefType rt = new SampleRefType();
rt.value = 44;
ModifyObject(rt);
System.Console.WriteLine(rt.value);
}
static void ModifyObject(SampleRefType obj){
obj.value = 33;
}
}
public static void TestRefType(){
SampleRefType rt = new SampleRefType();
rt.value = 44;
ModifyObject(rt);
System.Console.WriteLine(rt.value);
}
static void ModifyObject(SampleRefType obj){
obj.value = 33;
}
【方法的返回值】
方法的返回值类型可以是基本的数据类型,例如int、double、bool等。也可以是基本的对象类型object,还可以是void,如果一个方法的返回值类型是void,则这个方法不需要返回值。
如果返回类型(方法名称前列出的类型)不是 void,则方法可以使用 return 关键字来返回值。如果语句中 return 关键字的后面是与返回类型匹配的值,则该语句将该值返回给方法调用方。return 关键字还会停止方法的执行。如果返回类型为 void,则可使用没有值的 return 语句来停止方法的执行。如果没有 return 关键字,方法执行到代码块末尾时即会停止。具有非 void 返回类型的方法才能使用 return 关键字返回值。
若要使用从方法返回的值,调用方法可以在本来使用同一类型的值就已足够的任何位置使用方法调用本身。还可以将返回值赋给变量。
方法的返回值类型可以是基本的数据类型,例如int、double、bool等。也可以是基本的对象类型object,还可以是void,如果一个方法的返回值类型是void,则这个方法不需要返回值。
如果返回类型(方法名称前列出的类型)不是 void,则方法可以使用 return 关键字来返回值。如果语句中 return 关键字的后面是与返回类型匹配的值,则该语句将该值返回给方法调用方。return 关键字还会停止方法的执行。如果返回类型为 void,则可使用没有值的 return 语句来停止方法的执行。如果没有 return 关键字,方法执行到代码块末尾时即会停止。具有非 void 返回类型的方法才能使用 return 关键字返回值。
class SimpleMath{
public int AddTwoNumbers(int number1, int number2){
return number1 + number2;
}
public int SquareANumber(int number){
return number * number;
}
}
return number1 + number2;
}
public int SquareANumber(int number){
return number * number;
}
}
若要使用从方法返回的值,调用方法可以在本来使用同一类型的值就已足够的任何位置使用方法调用本身。还可以将返回值赋给变量。
int result = obj.AddTwoNumbers(1, 2);
obj.SquareANumber(result);
-或-
obj.SquareANumber(obj.AddTwoNumbers(1, 2));
-或-
obj.SquareANumber(obj.AddTwoNumbers(1, 2));
【方法的参数传递】
如果在为方法声明参数时未使用 ref 或 out,则该参数可以具有关联的值。可以在方法中更改该值,但当控制传递回调用过程时,不会保留更改的值。通过使用方法参数关键字,可以更改这种行为。
声明方法参数时可以使用的关键字:
如果在为方法声明参数时未使用 ref 或 out,则该参数可以具有关联的值。可以在方法中更改该值,但当控制传递回调用过程时,不会保留更改的值。通过使用方法参数关键字,可以更改这种行为。
声明方法参数时可以使用的关键字:
- ref
- out
- params
【ref参数】
ref 关键字使参数按引用传递。其效果是,当控制权传递回调用方法时,在方法中对参数的任何更改都将反映在该变量中。若要使用 ref 参数,则方法定义和调用方法都必须显式使用 ref 关键字。
传递到 ref 参数的参数必须最先初始化。这与 out 不同,后者的参数在传递之前不需要显式初始化。
尽管 ref 和 out 在运行时的处理方式不同,但在编译时的处理方式相同。因此,如果一个方法采用 ref 参数,而另一个方法采用 out 参数,则无法重载这两个方法。
如果一个方法采用 ref 或 out 参数,而另一个方法不采用这两个参数,则可以进行重载。
按引用传递值类型是有用的,但是 ref 对于传递引用类型也是很有用的。这允许被调用的方法修改该引用所引用的对象,因为引用本身是按引用来传递的。
ref 关键字使参数按引用传递。其效果是,当控制权传递回调用方法时,在方法中对参数的任何更改都将反映在该变量中。若要使用 ref 参数,则方法定义和调用方法都必须显式使用 ref 关键字。
class RefExample{
static void Method(ref int i){
i = 44;
}
static void Main(){
int val = 0;
Method(ref val);
// val is now 44
}
}
i = 44;
}
static void Main(){
int val = 0;
Method(ref val);
// val is now 44
}
}
传递到 ref 参数的参数必须最先初始化。这与 out 不同,后者的参数在传递之前不需要显式初始化。
尽管 ref 和 out 在运行时的处理方式不同,但在编译时的处理方式相同。因此,如果一个方法采用 ref 参数,而另一个方法采用 out 参数,则无法重载这两个方法。
class CS0663_Example{
// Compiler error CS0663: "cannot define overloaded
// methods that differ only on ref and out".
public void SampleMethod(ref int i) { }
public void SampleMethod(out int i) { }
}
编译出错
// methods that differ only on ref and out".
public void SampleMethod(ref int i) { }
public void SampleMethod(out int i) { }
}
如果一个方法采用 ref 或 out 参数,而另一个方法不采用这两个参数,则可以进行重载。
class RefOutOverloadExample{
public void SampleMethod(int i) {
}
public void SampleMethod(ref int i) { }
}
注意:属性不是变量,因此不能作为 ref 参数传递。
public void SampleMethod(ref int i) { }
}
按引用传递值类型是有用的,但是 ref 对于传递引用类型也是很有用的。这允许被调用的方法修改该引用所引用的对象,因为引用本身是按引用来传递的。
class RefRefExample{
static void Method(ref string s){
s = "changed";
}
static void Main(){
string str = "original";
Method(ref str);
// str is now "changed"
}
}
s = "changed";
}
static void Main(){
string str = "original";
Method(ref str);
// str is now "changed"
}
}
【out参数】
out 关键字会导致参数通过引用来传递。这与 ref 关键字类似,不同之处在于 ref 要求变量必须在传递之前进行初始化。若要使用 out 参数,方法定义和调用方法都必须显式使用 out 关键字。
注意:属性不是变量,因此不能作为 out 参数传递。
当希望方法返回多个值时,声明 out 方法很有用。使用 out 参数的方法仍然可以将变量作为返回类型来访问,但它还可以将一个或多个对象作为 out 参数返回给调用方法。
out 关键字会导致参数通过引用来传递。这与 ref 关键字类似,不同之处在于 ref 要求变量必须在传递之前进行初始化。若要使用 out 参数,方法定义和调用方法都必须显式使用 out 关键字。
class OutExample{
static void Method(out int i){
i = 44;
}
static void Main(){
int value;
Method(out value);
// value is now 44
}
}
尽管作为 out 参数传递的变量不必在传递之前进行初始化,但需要调用方法以便在方法返回之前赋值。
i = 44;
}
static void Main(){
int value;
Method(out value);
// value is now 44
}
}
注意:属性不是变量,因此不能作为 out 参数传递。
当希望方法返回多个值时,声明 out 方法很有用。使用 out 参数的方法仍然可以将变量作为返回类型来访问,但它还可以将一个或多个对象作为 out 参数返回给调用方法。
class OutReturnExample{
static void Method(out int i, out string s1, out string s2){
i = 44;
s1 = "I've been returned";
s2 = null;
}
static void Main(){
int value;
string str1, str2;
Method(out value, out str1, out str2);
// value is now 44
// str1 is now "I've been returned"
// str2 is (still) null;
}
}
i = 44;
s1 = "I've been returned";
s2 = null;
}
static void Main(){
int value;
string str1, str2;
Method(out value, out str1, out str2);
// value is now 44
// str1 is now "I've been returned"
// str2 is (still) null;
}
}
【params参数】
params 关键字可以指定在参数数目可变处采用参数的方法参数。
在方法声明中的 params 关键字之后不允许任何其他参数,并且在方法声明中只允许一个 params 关键字。
params 关键字可以指定在参数数目可变处采用参数的方法参数。
在方法声明中的 params 关键字之后不允许任何其他参数,并且在方法声明中只允许一个 params 关键字。
using System;
public class MyClass {
public static void UseParams(params int[] list){
for (int i = 0 ; i < list.Length; i++)
{
Console.WriteLine(list[i]);
}
Console.WriteLine();
}
public static void UseParams2(params object[] list){
for (int i = 0 ; i < list.Length; i++){
Console.WriteLine(list[i]);
}
Console.WriteLine();
}
static void Main(){
UseParams(1, 2, 3);
UseParams2(1, 'a', "test");
// An array of objects can also be passed, as long as
// the array type matches the method being called.
int[] myarray = new int[3] {10,11,12};
UseParams(myarray);
}
}
public static void UseParams(params int[] list){
for (int i = 0 ; i < list.Length; i++)
{
Console.WriteLine(list[i]);
}
Console.WriteLine();
}
public static void UseParams2(params object[] list){
for (int i = 0 ; i < list.Length; i++){
Console.WriteLine(list[i]);
}
Console.WriteLine();
}
static void Main(){
UseParams(1, 2, 3);
UseParams2(1, 'a', "test");
// An array of objects can also be passed, as long as
// the array type matches the method being called.
int[] myarray = new int[3] {10,11,12};
UseParams(myarray);
}
}
【方法重载】
可以使用一种称为“重载”的方法来创建一个方法的多个版本。如果一个类具有多个同名的方法,但每个方法都有不同的一组参数,则该方法会被重载。
每个类型成员都有一个唯一的签名。方法签名由方法名称和一个参数列表(方法的参数的顺序和类型)组成。只要签名不同,就可以在一种类型内定义具有相同名称的多种方法。当定义两种或多种具有相同名称的方法时,就称作重载。编译器知道在何种情况下应该调用哪个方法。
方法重载的两种方式:
可以使用一种称为“重载”的方法来创建一个方法的多个版本。如果一个类具有多个同名的方法,但每个方法都有不同的一组参数,则该方法会被重载。
每个类型成员都有一个唯一的签名。方法签名由方法名称和一个参数列表(方法的参数的顺序和类型)组成。只要签名不同,就可以在一种类型内定义具有相同名称的多种方法。当定义两种或多种具有相同名称的方法时,就称作重载。编译器知道在何种情况下应该调用哪个方法。
方法重载的两种方式:
- 参数是不同类型的重载
- 参数个数不同的重载
public class Add{
public int Sum(int para1, int para2){
return para1 + para2;
}
public int Sum(int para1, int para2, int para3){
return para1 + para2 + para3;
}
public string Sum(string para1, string para2){
return para1 + para2;
}
}
return para1 + para2;
}
public int Sum(int para1, int para2, int para3){
return para1 + para2 + para3;
}
public string Sum(string para1, string para2){
return para1 + para2;
}
}
【运算符重载】
C# 允许用户定义的类型通过使用 operator 关键字定义静态成员函数来重载运算符。但不是所有的运算符都可被重载。
注意:较运算符(如果重载)必须成对重载;也就是说,如果重载 ==,也必须重载 !=。反之亦然,< 和 > 以及 <= 和 >= 同样如此。
若要在自定义类中重载运算符,需要在该类中创建具有正确签名的方法。该方法必须命名为“operator X”,其中 X 是正在重载的运算符的名称或符号。一元运算符具有一个参数,二元运算符具有两个参数。在每种情况下,参数的类型必须与声明该运算符的类或结构的类型相同。
示例:
C# 允许用户定义的类型通过使用 operator 关键字定义静态成员函数来重载运算符。但不是所有的运算符都可被重载。
运算符
|
可重载性
|
+、-、!、~、++、--、true 和 false | 可以重载这些一元运算符。 |
+, -, *, /, %, &, |, ^, <<, >> | 可以重载这些二进制运算符。 |
==, !=, <, >, <=, >= | 比较运算符可以重载 |
&&, || | 条件逻辑运算符不能重载,但可使用能够重载的 & 和 | 进行计算。 |
[] | 不能重载数组索引运算符,但可定义索引器。 |
() | 不能重载转换运算符,但可定义新的转换运算符。 |
+=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>= | 赋值运算符不能重载,但 += 可使用 + 计算,等等。 |
=、.、?:、->、new、is、sizeof 和 typeof | 不能重载这些运算符。 |
若要在自定义类中重载运算符,需要在该类中创建具有正确签名的方法。该方法必须命名为“operator X”,其中 X 是正在重载的运算符的名称或符号。一元运算符具有一个参数,二元运算符具有两个参数。在每种情况下,参数的类型必须与声明该运算符的类或结构的类型相同。
public static Complex operator +(Complex c1, Complex c2)
示例:
public struct Complex
{
public int real;
public int imaginary;
public Complex(int real, int imaginary) //constructor
{
this.real = real;
this.imaginary = imaginary;
}
// Declare which operator to overload (+),
// the types that can be added (two Complex objects),
// and the return type (Complex):
public static Complex operator +(Complex c1, Complex c2)
{
return new Complex(c1.real + c2.real, c1.imaginary + c2.imaginary);
}
// Override the ToString() method to display a complex number in the traditional format:
public override string ToString()
{
return (System.String.Format("{0} + {1}i", real, imaginary));
}
}
class TestComplex
{
static void Main()
{
Complex num1 = new Complex(2, 3);
Complex num2 = new Complex(3, 4);
// Add two Complex objects through the overloaded plus operator:
Complex sum = num1 + num2;
// Print the numbers and the sum using the overriden ToString method:
System.Console.WriteLine("First complex number: {0}", num1);
System.Console.WriteLine("Second complex number: {0}", num2);
System.Console.WriteLine("The sum of the two numbers: {0}", sum);
}
}
public int real;
public int imaginary;
public Complex(int real, int imaginary) //constructor
{
this.real = real;
this.imaginary = imaginary;
}
// Declare which operator to overload (+),
// the types that can be added (two Complex objects),
// and the return type (Complex):
public static Complex operator +(Complex c1, Complex c2)
{
return new Complex(c1.real + c2.real, c1.imaginary + c2.imaginary);
}
// Override the ToString() method to display a complex number in the traditional format:
public override string ToString()
{
return (System.String.Format("{0} + {1}i", real, imaginary));
}
}
class TestComplex
{
static void Main()
{
Complex num1 = new Complex(2, 3);
Complex num2 = new Complex(3, 4);
// Add two Complex objects through the overloaded plus operator:
Complex sum = num1 + num2;
// Print the numbers and the sum using the overriden ToString method:
System.Console.WriteLine("First complex number: {0}", num1);
System.Console.WriteLine("Second complex number: {0}", num2);
System.Console.WriteLine("The sum of the two numbers: {0}", sum);
}
}
【不同类型的参数传递】
值方式参数传递 - 没有使用ref
(1)值传递值类型:在程序中不会修改值类型参数的值。
(2)值传递引用类型(传递方式还是值方式,即没有使用ref):当引用变量发生变化时,参数发生了变量。所以,当类作物参数时,参数被修改时,可能修改类成员的值。
引用方式参数传递 - 所用了ref
(1)引用方式传递引用类型:
(2)应用方式传递值类型:
两种情况下都会发生改变,及ref方式传递来中类型没有区别,都会保存方法的修改。
数组作为参数,在方法中修改后,数组中的值也会发生变化,所以说,数组是引用类型。一般说来,除了枚举和结构,其他的都是引用类型。
值方式参数传递 - 没有使用ref
(1)值传递值类型:在程序中不会修改值类型参数的值。
(2)值传递引用类型(传递方式还是值方式,即没有使用ref):当引用变量发生变化时,参数发生了变量。所以,当类作物参数时,参数被修改时,可能修改类成员的值。
引用方式参数传递 - 所用了ref
(1)引用方式传递引用类型:
(2)应用方式传递值类型:
两种情况下都会发生改变,及ref方式传递来中类型没有区别,都会保存方法的修改。
数组作为参数,在方法中修改后,数组中的值也会发生变化,所以说,数组是引用类型。一般说来,除了枚举和结构,其他的都是引用类型。
【对象作为参数】
当对象作为函数参数时,在函数中只能改变该对象的状态,但不能改变该对象的引用
class Test{
当对象作为函数参数时,在函数中只能改变该对象的状态,但不能改变该对象的引用
class Test{
int a,b;
Test(int i,int j) {
a=i;
b=j;
}
//可以在函数中改变对象状态
void change(Test obj) {
obj.a=50;
obj.b=40;
}
} // 改变对象状态
Test(int i,int j) {
a=i;
b=j;
}
//可以在函数中改变对象状态
void change(Test obj) {
obj.a=50;
obj.b=40;
}
} // 改变对象状态
void swapobj(Day x,Day y){
Day temp=y;
y=x;
x=temp;
} // 引用本身按值传递
y=x;
x=temp;
} // 引用本身按值传递