C# 类和编程案例

一.
    “类”是一种构造,通过使用该构造,您可以将其他类型的变量、方法和事件组合在一起,从而创建自己的自定义类型。如果类没有声明为静态类,客户端代码就可以创建赋给变量的“对象”或“实例”,从而使用该类。在对变量的所有引用都超出范围之前,该变

量始终保持在内存中。所有引用都超出范围时,CLR 将标记该变量以供垃圾回收。如果类声明为静态类,则内存中只存在一个副本,并且客户端代码只能通过该类自身而不是“实例变量”访问该类。
    与结构不同,类支持“继承”,而继承是面向对象编程的基础特性。
    类使用 class 关键字进行声明。
    class 关键字前面是访问级别。如果使用 public,任何人都可以基于该类创建对象。
    对象是基于类的具体实体,有时称为类的实例。通过使用 new 关键字(后跟对象将基于的类的名称)可以创建对象。
    由于基于类的对象是按引用来引用的,因此类称为引用类型。
    this关键字提供对当前实例的访问。

二.
类继承
继承是通过使用“派生”来实现的,而派生意味着类是使用“基类”声明的,它的数据和行为从基类继承。通过在派生的类名后面追加冒号和基类名称,可以指定基类,例如,
public class Manager : Employee
{
    // Employee fields, properties, methods and events are inherited
    // New Manager fields, properties, methods and events go here...
}

当类声明基类时,它继承基类除构造函数以外的所有成员。
与 C++ 不同,C# 中的类只能直接从一个基类继承。但是,因为基类自身也可能继承自另一个类,所以类可以间接继承多个基类。而且,一个类可以直接实现一个以上的接口。

类可以声明为抽象类。抽象类包含具有签名定义但没有实现的抽象方法。抽象类不能进行实例化。只能通过实现抽象方法的派生类使用抽象类。相比之下,密封类不允许其他类从其派生。

类定义可在不同的源文件之间进行拆分,这叫分部类。


三.
一个类对象中,主要包括字段、属性和方法。不过除此之外,在类类型中还可以定义嵌套类,也可以定义一个常量。

常量:
const PI = 3.1415926;
square = PI * radius;

类的字段其实也是变量。字段仍然可以利用public,internal,protected,private来修饰它。不过,建议如非特殊情况,不要将字段修饰为public。因为,根据”对象封装”的原则,应尽量避免将一个类型的字段以公有方式提供给外部。毕竟,对于字段而言,对象对

它的控制非常弱,一旦公开在外,则调用者可以比较容易的对其进行操作,尤其是写操作,从而可能会导致错误。例如,如果为User类增加一个age(年龄)字段,假如将其定义为public字段,
public int Age;
 
那么调用者可能会将Age的值设为负数:
user.Age = -5;

如果字段不能设置为public,那么调用者又如何访问它们呢?使用C#类中的property(属性)。

“属性”,它利用一种被称为“get/set访问器”分别控制对字段的读写操作,并暴露一个属性值,如Age属性:
private int m_age;
public int Age
{
 get {return m_age;}
 set
 {
  if (value < 0)
  {
   throw new ArgumentOutOfRangeException("Age must be greater than or equal to 0");
  }
  m_age = value;
 }
}
 
首先,定义一个私有字段m_age,然后再定义一个公共属性Age。在该属性中,get返回私有字段的值m_age,而在set中,首先会判断value的值,如果小于0,那么这个值是非法的,就将抛出一个异常,停止往下执行,并告诉你对Age值的设置错误了。当然,也可以为value

值设置更严格的要求,例如不允许value大于150。
 
value是什么?它是C#中提供的关键字,代表的是赋给该属性的真正的值,例如:
user.Age = 30;

此时是对Age属性赋值,.Net会执行set访问器,而value值就是30。然后判断30是否小于0。符合条件,不会抛出异常,继续执行,将value值30赋给字段m_age。
为什么要赋给m_age呢?看看get访问器,它其实就是一个读操作,返回的值是什么?就是字段m_age,如下所示:
user.Age = 30;     //set操作,将字段m_age设置为30;
Console.WriteLine(“User’s Age is {0}.”, user.Age);   //get操作,将m_age的值取出;
 
此时就会在控制台下显示:
User’s Age is 30.
 
此外,对于一些特殊的要求,我们在将字段封装为属性时,可以只设置它的get访问器或者set访问器,这样这个属性就是只读属性,或者只写属性了。这样更有利于对象的封装。
毕竟对于公共字段而言,我们最能可以控制它为只读(设置为readonly),却无法设置为只写。
 
从上可以看到,实际上属性就是对字段进行一次封装。

在C# 2.0中,除了可以对整个属性设置public等访问修饰符外,对内部的get/set访问器同样可以设置访问修饰符,当然它要受到一定的限制。

访问器和属性的访问修饰符冲突问题。
1、如果整个属性被设置为public,则其访问器没有限制;
2、如果整个属性被设置为protected internal,则访问器的访问修饰仅能设置为internal,protected或者private中的一种;
3、如果整个属性被设置为internal或者protected,那么访问器的访问修饰只能是private。


1 使用this进行串联构造函数调用
使用一项名为构造函数链的技术来设计类。当类定义个了多个构造函数时,这个设计模式就会很有用。
由于构造函数通常会检验传入的参数来强制各种业务规则,所以在类的构造函数集合中经常会找到冗余的验证逻辑。
串联构造函数方案:让一个接受最多参数个数的构造函数做“主构造函数”,并实现必须的验证逻辑。其余的构造函数使用this关键字把参数转给主构造函数,并提供其他必需的参数。这样,我们只关心主构造函数的逻辑,而其他构造函数体基本是空的了。
使用this关键字串联构造函数方式可以简化编程任务,类定义更加容易维护、更更加简明。但它不是强制使用的。
 
串联构造函数的执行顺序:
1、调用构造函数把调用者提供的参数值转发给主构造函数,并提供其他必须的初始化参数值。
2、执行主构造函数。
3、执行调用构造函数体的逻辑。

2 自定义索引器

class CarCollection:IEnumerable{
   private ArrayList arCar=new ArrayList();
   public Car this[int index]
   {
      get{ return (Car)arCar[index];}
      set{arCar.Insert(index,value);}
   }
   //...
}

3 static关键字
    C#类(或者结构)可以使用static关键字来定义许多静态成员。这些静态成员只能从类级别而不能从对象级别上调用(调用静态成员时不需要创建实例对象)。
 
例如:
//错误,WriteLine是静态成员,是类级别的方法。
Console c=new Console();
c.WriteLine("Bruce Wong");

//正确!WriteLine是类级别的方法
Console.WriteLine("Bruce Wong");

静态成员只能操作静态数据或调用类的静态成员。而非静态成员可以操作实例数据与静态数据(成员),因为静态成员对类的所有实例都是可用的。
CLR把静态数据分配到内存只进行一次,改变静态数据将影响此类的所有实例。
 
定义静态构造函数
    构造函数用于在创建类对象时设置类对象的数据值。如果使用实例级别的构造函数给静态数据赋值,你会发现每次新建类对象时静态数据的只都会被重置。所以我们要初始化静态数据最好使用静态构造函数。
 
    静态构造函数是特殊的构造函数,它非常适用于初始化在编译时未知的静态数据的值:
    一个类(结构)只能定义一个静态构造函数。
    静态构造函数不允许访问修饰符并且不能接受任何参数。
    无论创建多少个类实例,静态函数知执行一次。
    CLR创建类实例或首次调用类静态成员前,CLR会调用静态构造函数。
    静态构造函数先于实例级别的其他构造函数执行。
 
    静态类:一个类被定义为静态的(使用static关键字修饰),就不能使用new关键字来创建类实例,静态类只能包含用static标记的静态类成员或

五 案例

1

码码:

using System;

public class Person
{
    // 字段
    public string name;

    // 无参构造函数
    public Person()
    {
        name = "不知道";
    }

    // 带一个参数构造函数
    public Person(string nm)
    {
        name = nm;
    }

    // 方法
    public void SetName(string newName)
    {
        name = newName;
    }
}
class TestPerson
{
    static void Main()
    {
        // 调用无参构造函数
        Person person1 = new Person();
        Console.WriteLine(person1.name);

        person1.SetName("张三");
        Console.WriteLine(person1.name);

        // 调用带一个参数构造函数
        Person person2 = new Person("李四");
        Console.WriteLine(person2.name);

        // 等待拿下键再关闭控制台窗口
        Console.WriteLine("按任意键继续......");
        Console.ReadKey();
    }
}
// Output:
// unknown
// John Smith
// Sarah Jones

图图:

2

码码:

/*
 * Created by SharpDevelop.
 * User: Administrator
 * Date: 2015/3/31
 * Time: 13:04
 *
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */
using System;

namespace leidemo2
{
 public class Car{
 //Car的字段(状态)
     private int _speed;
     private string _name;

 //Car操作字段的属性
     public int Speed    {
        set {this._speed=value;}
        get{return this._speed;}
  }

 public string Name
    {
        set { this._name=value;}
        get{return this._name;}
 }

     //显式定义默认构造函数
     public Car(){}

     //自定义构造函数
     public Car(string name,int speed)
    {
        this._name=name;
        this._speed=speed;
 }

 //Car的功能(方法)
 public void ShowState()
 {
  Console.WriteLine("车 {0} 的速度是 {1} MPH", this._name,this. _speed);
 }
 }
 
 class Program
 {
  public static void Main(string[] args)
  {
   //创建Car对象。
   Car car; //声明了指向尚未创建的Car对象的引用。
   car=new Car("宝马",150);//通过new把有效的引用赋给对象,这引用才会指向内存有效的对象。
   car.ShowState();
   
   Console.Write("按任意键继续 . . . ");
   Console.ReadKey(true);
  }
 }
}

图图:

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值