我是如何学习c#语言的-勤奋才是王道-第二部分

类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类
第二部分 类的基础知识
类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类
一综合
1 类的修饰符
public 表示不限制对类的访问
protected 表示只能从所在类和所在类的派生自类进行访问
internal 表示只有所在类才能访问
private 只有系统定义的库或者包才能访问
abstract 抽象类,不允许建立类的实例
sealed 密封类 不允许被继承
2 类的成员
成员常量
字段
属性
方法
事件
索引
构造函数
析构函数
3 this关键字的使用
4面向对象语言的特点:
封装(black boxing黑盒)
实现方法:例如 创建一个类 圆 ,封装圆的信息,可能包括 半径 周长,面积 位置等
还可能包括一些方法 计算面积 计算周长,所有的计算过程被封装起来, 我们只要
根据函数名调用相应方法 来计算周长 或面积 而不用去理会 到底计算周长的具体代码是
是怎么实现的,如果需要知道圆的相关信息 可以访问圆的 字段 (在c#中一般将字段设置为
private 而设置 属性来对字段(信息)的访问
多态 为什么要用多态的原因 举例说明
1
比如计算圆的面积,为了方便用户使用,我们可以提供多种方法
1用户只要输入圆上的三个点的坐标 或者 输入圆的半径和圆心的坐标
都可以得到圆的面积,这就可以通过多态来实现
继承
重用
5类的自定义一些规则:
当你定义类的成员名时,不要忘了对公有成员使用PascalCase规则,
而对非公有成员使用camelCase规则。
类的声明中虽然可以使用结尾分号,但建议你不要使用,
这只不过是为了照顾C++程序员的习惯。

class Pair 
    public int X, Y; //公有变量名单词的首字母大写(PascalCase规则)
}
class Pair 
    private int x, y; //非公有变量名第一个单词的首字母小写(camelCase规则)
}
class Pair 
   int x, y; //缺省的访问修饰符是private
};//可以有结尾分号一般不写)

二命名空间
实际中的 C#程序通常包含多个文件,其中每个文件都可以包含一个或多个名称空间。
使用namesapce关键字,我们还可以将C#程序或者类包裹在自身的名称空间中
namespace MyOwn
{
using System; // for String
class MyFirstApp
{
   static int Main(String[] args) 
   {
       System.Console.WriteLine ("Hello .NET");
return 1;
   }
}
}


三装箱和拆箱
四变量 
静态变量与非静态变量(又称实例变量)
  变量的类型:
静态static variables
非静态 instance variables
数组元素 array elements
值参数 value parameters
引用参数 reference parameters
输出参数 output parameters
局部变量 local variables
局部变量是指在一个独立的程序块中声明的变量,如for switch using等
它只在该范围内有效
局部变量 和其他变量不一样 系统不会给它指明一个默认值

五属性与字段(有的教材叫域)
1字段
字段类似c++中的简单成员变量例如:
class A
{
public int x;
  publicstring y;
private flort z;
}
2静态字段和非静态字段
1
和前面讲的讲台变量和非静态变量的用法 原理 一样
若将一个字段说明为静态的,无论建立多少类的实例,内存中只有一个静态数据的拷贝
当这个类的第一个实例被初始化时,静态字段就被初始化了,以后再次建立实例的时候
不再对其初始化,所有的类的实例共享一个静态字段副本
与静态字段相反,非静态字段在类每次进行实例化的时候,每个实例都有一份单独的拷贝
   下面例子显示了一个 Color 类,
它包含三个分别名为 redPart、bluePart 和 greenPart 的内部实例字段
和四个分别名为 Red、Blue、Green 和 White 的静态字段
class Color
{
public static Color Red = new Color(0xFF, 0, 0);
public static Color Blue = new Color(0, 0xFF, 0);
public static Color Green = new Color(0, 0, 0xFF);
public static Color White = new Color(0xFF, 0xFF, 0xFF);
internal ushort redPart;
internal ushort bluePart;
internal ushort greenPart;
public Color(ushort red, ushort blue, ushort green) 
{
redPart = red;
bluePart = blue;
greenPart = green;
}
}
2
3readonly的相关知识
4常量字段
?       隐含为static 
?       必须在声明时初始化
?       必须被初始化为编译时常量值 
?       只有简单类型,枚举,字符串才可以是常量
struct Pair 
    public Pair(int x, int y) 
    { 
        // ??? 
  
    ...
    private const int x = 0, y = 0;
}
在C#中,常量字段隐含为static,但你不能显式声明一个常量字段是static:
static const int x = 0;//错误
常量必须被初始化,并且只能在声明时初始化:
const int x;//错误
常量必须被初始化为编译时常量值:
const int x = Method();//错误
只有简单类型,枚举,字符串才能被声明为常量:
const Pair p = new Pair();//错误

3属性 get set 
1概述
属性的引进,体现了对象的封装性:不直接操作了的数据内容,而是通过访问其对其访问
利用get 和set 对属性进行读 写
只有set访问器 表明属性的值只能进行设置吧不能读出
  只有get访问器 表明属性的值只读 不能改写
同时具有set和get访问器 表明属性的值 读写 都是允许的
get 要和 return 结合使用 来读取属性的值
set 要和 value 结合使用来设置属性的值

2 get 语句举例:
?       必须返回一个有确定类型的值 
?     功能上就像一个 “get 函数”
struct Time 
    ... 
   public int Hour 
   {   
       get 
      { 
           return hour; 
      } 
      ... 
  
   private int hour, minute, second; 
}
Time lunch = new Time(); 
... Console.WriteLine(lunch.Hour);
//请注意,get和set不是关键字
当读一个属性的时候,属性的get语句自动运行。
get语句必须返回一个有确定类型的值。在上面的例子中,Time结构类有一个整型属性Hour,所以它的get语句必须返回一个整型值。
属性的返回值不能是void(从这里可以推断出字段的类型也不能是void)。这就意味着get语句必须包含一个完整的return语句(retun;这种形式是错误的)。
get语句可以在retun语句前包含任何其他的语句(比如,可以检查变量的类型),但return语句不能省略。
注意,get和set不是关键字,所以你可以在任何地方包括get/set语句中声明一个局部变量、常量的名字是get或set,但最好不要这样做

  3 set 语句举例:
?      是通过value 标识符来进行赋值的
?        可以包含任何语句(甚至没有语句)
struct Time 
    ... 
    public int Hour 
   {   
       ... 
      set { 
          if (value < 0 || value > 24) 
               throw new ArgumentException("value"); 
           hour = value; 
      } 
  
   private int hour, minute, second; 
}
Time lunch = new Time(); 
... 
lunch.Hour = 12;
当写一个属性的时候,属性的set语句自动运行。
在上面的例子中,Time结构类有一个整型属性Hour,所以赋给这个属性的值必须是一个整型值。例如:
lunch.Hour = 12;
把一个整型值12赋给了lunch的Hour属性,这个语句会自动调用属性的set语句。
set语句是通过value标识符来获得属性的赋值的。例如,如果12被赋给了Hour属性,那么vaue的值就是12。
注意的是value不是一个关键字。value只是在set语句中才是一个标识符。你可以在set语句外的任何语句声明value为一变量的名字。
例如:
public int Hour
{
get { int value; ... }//正确
set { int value; ... }//错误
}

4只读属性
?       只读属性只有get语句 
?       任何写操作都会导致错误 
?       就像一个只读字段
struct Time 
    ... 
   public int Hour 
   {   
        get 
      
           return hour; 
        } 
  
   private int hour, minute, second; 
}
Time lunch = new Time(); 
... 
lunch.Hour = 12; //错误
... 
lunch.Hour += 2;//错误
一个属性可以不必同时声明get语句和set语句。你可以只声明一个get语句。在这种情况下,属性是只读的,任何写的操作都会导致错误。例如,下面的语句就会导致一个错误:
lunch.Hour = 12;
因为Hour是只读属性。
但要注意的是,属性必须至少包括一个get或set语句,一个属性不能是空的:
public int Hour { }//错误
5只写属性
?     只写属性只能有set 语句
?      任何读操作都是错误的
struct Time 
   ... 
   public int Hour 
   {   
       set { 
           if (value < 0 || value > 24) 
                throw new OutOfRangeException("Hour"); 
           hour = value; 
      
    
   private int hour, minute, second; 
}
Time lunch = new Time(); 
... 
Console.WriteLine(lunch.Hour); //错误
... 
lunch.Hour += 12;//错误
一个属性可以不必同时声明get语句和set语句。你可以只声明一个set语句。在这种情况下,属性是只写的,任何读的操作都会导致错误。例如,下面的语句就会导致一个错误:
Console.WriteLine(lunch.Hour);
因为Hour是只写属性。
而下面的例子则看上去好像是对的:
lunch.Hour += 2;
这句语句的实际运作是这样的:
lunch.Hour = lunch.Hour + 2;
它执行了读的操作,因此是错误的。因此,像+=这种复合型的赋值操作符既不能用于只读属性,也不能用于只写属性。
  6综合举例
在下面的示例中,Button 类定义一个 Caption 属性。 
public class Button 
{
private string caption;
public string Caption 
{
get 
{
return caption;
}
set 
{
caption = value;
Repaint();
}
}
}
可读取并写入的属性(如 Caption)同时包含 get 和 set 访问器。
当读取属性值时调用 get 访问器;当写入属性值时则调用 set 访问器。
在 set 访问器中,属性的新值是通过一个名为 value 的隐式参数来赋值的。
属性声明相对直接一些,但是属性的实际值在它们被使用时才可见。
例如,读取和写入 Caption 属性的方式可以与读取和写入字段相同:
Button b = new Button();
b.Caption = "ABC"; // set; causes repaint
string s = b.Caption; // get
b.Caption += "DEF"; // get & set; causes repaint


六方法(函数)
1基本语法
C#不支持全局函数 
       所有的函数必须在类内部声明
       无源文件和头文件之分 
       所有的函数必须声明的时候被实现
函数不能有结尾分号
  sealed class Methods 
    void Inline() 
    { ... 
    } 
    void Error() 
    { ... 
    };                   //错误,函数不能有结尾分号

C#允许可以在类的声明中加入结尾分号,例如:
sealed class Methods
{
...
};//可以有结尾分号
但是,C#不允许在函数的声明中加入结尾分号,例如:
sealed class Methods
{
void NotAllowed() {...} ; //错误,函数不能有结尾分号
}

2函数重载
一个类中的函数可以有同一个名字,称为重载
函数名和参数称为标识 
标识必须唯一
返回值类型不是标识
和C++与Java一样,C#允许一个类声明两个以上的同名函数,只要参数的类型或个数不同。这就是重载。
但是,一个类不能包含标识为相同的实例函数和静态函数
namespace System 
{
   public sealed class Console 
      {
         public static void WriteLine() 
         { ... } 
         public static void WriteLine(int value) 
         { ... } 
         public static void WriteLine(double value) 
         { ... } 
          ... 
         public static void WriteLine(object value) 
         { ... } 
          ... 
           } 
}
注意:
和C++与Java一样,返回值的类型不是标识的一部分,不能被用作重载的标准,例如:
sealed class AlsoIllegal
{
int Random() { ... }
double Random() { ... }//错误
3ref和out重载
ref / out 在大部分情况下是标识的一部分! 
      你可以重载一个ref型参数和一个普通参数 
      你可以重载一个out型参数和一个普通参数 
      你不可以重载一个ref型参数和一个out型参数
sealed class Overloading 
{
    void Allowed(    int parameter) 
    { ... } 
    void Allowed(ref int parameter) 
    { ... } 
   //正确,重载一个ref型参数和一个普通参数
 
    void AlsoAllowed(    int parameter) 
    { ... } 
    void AlsoAllowed(out int parameter) 
{ ... }
//正确,重载一个out型参数和一个普通参数

    void NotAllowed(ref int parameter) 
    { ... } 
   void NotAllowed(out int parameter) 
{ ... }
//错误,不能重载一个ref型参数和一个out型参数
}
ref和out修饰符可以是一个函数的标识。但是你不能同时重载ref和out型参数。
ref和out修饰符在某种意义上是“安全的“,因为只有ref型实参才能传递给ref型函数参数,
只有out型实参才能传递给out型函数参数。
但是,当调用函数的时候,你会非常容易忘记ref和out修饰符,所以最好不要重载ref和out型参数。
例如:
sealed class Overloading
{
public static void Example(int parameter)
{ ... }
public static void Example(ref int parameter)
{ ... }
static void Main()
{
int argument = 42;
Example(argument);//在这儿非常容易忘记ref修饰符
}
}

4方法中的参数
1
总说:
值参数
引用参数ref 用ref修饰
输出参数out 用out修饰
数组行参数 用params修饰
2
值参数:
没有被ref 或 out修饰的函数参数是一个值型参数。
值型参数只有在该参数所属的函数被调用的时候才存在,并且用调用时所传递的实参的值来进行初始化。
当函数调用结束时,值型参数不复存在

只有被预先赋值的实参才能被传递给值型参数,例如:
int arg;    // arg没有被赋初值
Method(arg);//错误,实参必须预先赋初值

传递给函数的实参可以是纯粹的数而不是变量,例如:
Method(42);
Method(21 + 21);
3
引用型参数
引用型参数是实参的一个别名 
没有发生复制 
实参必须预先被赋值
实参必须是一个变量类型 
实参和函数参数都要有ref
sealed class ParameterPassing 
{
   static void Method(ref int parameter) 
   { 
        parameter = 42; 
    } 
    static void Main() 
    { 
       int arg = 0; 
       Console.Write(arg); //结果为0
       Method(ref arg); 
       Console.Write(arg); //结果为42
    } 
}
函数参数有ref修饰符时,被称为引用型参数。引用型参数不产生新的存储区间。实际上,引用型参数是函数调用时所传递的实参所代表的变量的别名。结果是引用型参数只是实参所代表的变量的另一个名字。
ref修饰符必须同时出现在函数声明语句和函数调用语句中。
只有被预先赋值的实参才能被传递给引用型参数,例如:
int arg;    // arg没有被赋初值
Method(ref arg);//错误,实参必须预先赋初值
传递给引用型参数的实参必须是变量类型,而不能是纯粹的值或常量。
Method(ref 42);  //错误,引用型参数的实参不能是纯粹的值
const int arg = 42;
Method(ref arg); //错误,引用型参数的实参不能是常量
4
out型参数
         out型参数是实参的一个别名 
       没有发生复制 
        实参不必预先赋值 
       实参必须是变量类型 
        函数参数必须被预先赋值才能使用 
        实参和函数参数都要有out
sealed class ParameterPassing 
{
    static void Method(out int parameter) 
    { 
       parameter = 42; 
  
   static void Main() 
  
        int arg; 
       //Console.Write(arg); 
        Method(out arg); 
        Console.Write(arg); //结果为42
    } 
}
函数参数有out修饰符时,被称为out型参数。out型参数不产生新的存储区间。实际上,out型参数是函数调用时所传递的实参所代表的变量的别名。结果是out型参数只是实参所代表的变量的另一个名字。
out修饰符必须同时出现在函数声明语句和函数调用语句中。
没有被预先赋值的实参能够被传递给引用型参数,例如:
int arg;    // arg没有被赋初值
Method(out arg);//正确,实参可以不赋初值
传递给out型参数的实参必须是变量类型,而不能是纯粹的值或常量。
Method(out 42);  //错误,out型参数的实参不能是纯粹的值
const int arg = 42;
Method(out arg); //错误,out型参数的实参不能是常量
5
ref与out区别
ref:
static void Main() 
    
        int arg = 0; //ref必须要初始化,在用,而out不用初始化
        Console.Write(arg); 
        Method(ref arg); 
        Console.Write(arg); 
    
out:
  static void Main() 
    { 
       int arg; 
       Method(out arg); //没有初始化
        Console.Write(arg); 
    } 
6
参数数组
参数数组用 params 修饰符声明。
一个给定的方法只能有一个参数数组,而且它必须始终是最后一个指定的参数。
参数数组的类型总是一维数组类型。
using System;
class Test 
{
static void F(params int[] args) {
Console.WriteLine("# of arguments: {0}", args.Length);
for (int i = 0; i < args.Length; i++)
Console.WriteLine("\targs[{0}] = {1}", i, args[i]);
}
static void Main() {
F();
F(1);
F(1, 2);
F(1, 2, 3);
F(new int[] {1, 2, 3, 4});
}
}
显示了带数目可变的 int 参数的方法 F,以及对此方法的若干个调用。输出为:
# of arguments: 0
# of arguments: 1
args[0] = 1
# of arguments: 2
args[0] = 1
args[1] = 2
# of arguments: 3
args[0] = 1
args[1] = 2
args[2] = 3
# of arguments: 4
args[0] = 1
args[1] = 2
args[2] = 3
args[3] = 4
七静态 static 非静态
1静态成员与非静态成员
  若将类中的某个成员声明为static
该成员成为静态成员
类中的成员要么是静态,要么是非静态的
非静态成员为实例专用,只有被实例化了
非静态成员才有意义
静态成员在内存中只有一个区域,而非静态成员与类的实例联系在一起,每当创建一个实例,系统会为创建 的实例创建一个非静态成员
这样在内存区域中有多个副本
静态成员使用举例:
1可以统计创建了多少个类的实例
2
2静态与非静态方法
  理解这个静态方法 可以联想 Console.WriteLine() 这个方法就是静态的

posted @ 2009-09-23 18:19  书奎  阅读(282)  评论(0编辑  收藏  举报