C#基础篇---1

C#把数据类型分为两种
值类型 和 引用类型
这两种类型存储在内存的不同地方:值类型存储在堆栈中,而引用类型存储在托管堆上。

CTS类型
C#认可的基本预定义类型并没有内置于语言中,而是内置于.NET Framework中。例如,在C#中声明一个int类型的数据时,声明的实际上是.NET结构System.Int32的一个实例。

1. 整型

2.浮点类型


float f = 12.3F;

3. decimal类型


decimal d = 12.30M;

4. bool类型


如果试图使用0表示false,非0值表示true,就会出错。

5. 字符类型


char类型的字面量是用单引号括起来的,例如'A'。如果把字符放在双引号中,编译器会把它看作是字符串,从而产生错误。

6.预定义的引用类型


a.object类型
   object类型就是最终的父类型,所有内在和用户定义的类型都从它派生而来。
b.string类型
String对象保留在堆上,而不是堆栈上。当把一个字符串变量赋给另一个字符串时,会得到对内存中同一个字符串的两个引用。但是修改其中一个字符串,会创建一个全新的string对象,而另一个字符串没有改变(这实际上是运算符重载的结果)。
  字符串中的转义字符:/和@
   字符串的属性:
   Length 字符串的字符长度
   字符串的方法:
      s.TrimStart();
      s.TrimEnd();
      s.Trim();
      s.ToUpper();
      s.ToLower();
      s.ToCharArray();
      s.Substring(int start[,int length]);
      s.Split([int n]);
      s.Replace(string old,strinig new);
      s.LastIndexOf(string str);
     s.IndexOf(string str);
重复修改给定的字符串,效率会很低,它实际上是一个不可变的数据类型,一旦对字符串对象进行了初始化,该字符串对象就不能改变了。修改字符串内容的方法和运算符实际上是创建一个新的字符串。
如果使用string类型的变量对字符串进行大量的拼接的时候,就会在内存中产生大量的垃圾对象,并且每次拼接字符串的时候都会生成一个新的对象,这样是很影响程序的性能。为了解决这个问题,Microsoft提供了System.Text.StringBuilder类。

7.StringBuilder类
StringBuilder不像String功能那么强大,在StringBuilder上可以用在需要大量的修改字符串中的文本的场景中。但是,它的工作方式非常高效。
两个主要的属性
  Length指定字符串的实际长度;
   Capacity是字符串占据存储单元的长度。
最好把容量设置为字符串可能的最大长度,确保StringBuilder不需要重新分配内存。
StringBuilder构造函数
  StringBuilder sb = new StringBuilder("Hello"); //用一个字符串初始化StringBuilder
   StringBuilder sb = new StringBuilder(20); //初始化一个空的StringBuilder ,其容量是20个字符
   StringBuilder sb = new StringBuilder(100, 500); //初始化一个StringBuilder对象,其最初的容量是100个字符,最大容量是500字符。若是超范围就会产生异常

8.日期时间函数
属性:
  Now:当前时间
   Today:今天
   Year:时间的年份
   Month:时间的月份
   Day:时间的日期
   Hour:时间的小时
   Minute:时间的分钟
   Second:时间的秒
   DayOfWeek:时间的星期
   DayOfYear:时间是一年中的第几天
   Date:日期部分
方法:
AddYears:对年份计算
   AddMonths:对月份计算
   AddDays:对日期计算
   AddHours(int):对小时计算
   AddMinutes(int):对分钟计算
   AddSeconds(int):对秒计算
   ToLongDateString():把时间转换为本地的长日期格式,如:中国的“yyyy年MM月dd日”
   ToShortDateString():把时间转换为本地的短日期格式,如:中国的“yyyy-MM-dd”
   ToLongTimeString():把时间转换为本地的长时间格式,如:中国的“hh:mm:ss”
   ToShortTimeString():把时间转换为本地的短时间格式,如:中国的“hh:mm”
  
9.格式化字符串
标准数字格式字符串
  C 或 c 货币:数字转换为表示货币金额的字符串。
D 或 d 十进制:只有整型才支持此格式。
   如:
   Console.WriteLine(MyDouble.ToString("C"));
    Console.WriteLine(MyDouble.ToString("E"));
    Console.WriteLine(MyDouble.ToString("P"));
    Console.WriteLine(MyDouble.ToString("N"));
    Console.WriteLine(MyDouble.ToString("F"));
   运算结果:
   $123,456,789.00
    1.234568E+008
    12,345,678,900.00%
    123,456,789.00
    1234567 .00
自定义数字格式字符串
  0 零占位符
   # 数字占位符
   . 小数点
   , 千位分隔符和数字比例换算
   % 百分比占位符
   如:
   double n = 1234567890.9;
     Response.Write(n.ToString("C")+"<br>");
     Response.Write(n.ToString("C4")+"<br>");
     Response.Write(n.ToString("RMB#,###.###")+"<br>");
     Response.Write(n.ToString("RMB#,###.000") + "<br>");
     Response.Write(n.ToString("RMB#")+"<br>");
    运行结果
   ¥1,234,567,890.90
    ¥1,234,567,890.9000
    RMB1,234,567,890.9
    RMB1,234,567,890.900
    RMB1234567891


格式化日期
   如:
   DateTime dt = DateTime.Now;
     Response.Write(dt.ToString("F")+"<br>");
     Response.Write(dt.ToString("yyyy年MM月dd日hh时mm分ss秒")+"<br>");
     Response.Write(dt.ToString("星期ddd"));
   运行结果:
   2008年7月10日 8:37:32
    2008年07月10日08时37分32秒
    星期四
  
10.常量
声明和初始化变量时,在变量的前面加上关键字const,就可以把该变量指定为一个常量。顾名思义,常量是其值在使用过程中不会发生变化的变量:
如:const int a = 100;
注意:
   常量必须在声明时初始化。指定了其值后,就不能再修改了。
  常量总是静态的。但注意,不必(实际上,是不允许)在常量声明中包含修饰符static。
  常量用易于理解的清楚的名称替代了“含义不明确的数字或字符串”,使程序更易于阅读。
   常量使程序更易于修改。
   常量更容易避免程序出现错误。可以防止把另一个值赋给程序中的一个常量。

11.枚举
枚举是用户定义的整数类型。所以枚举类型可以强制转换为整型。
如果在代码的某个地方,要试图把一个不在可接受值范围内的值赋予枚举的一个实例,编译器就会报告一个错误。
使用枚举比使用无格式的整数至少有如下三个优势:
  a.枚举可以使代码更易于维护,有助于确保给变量指定合法的、期望的值。
   b.枚举使代码更清晰,允许用描述性的名称表示整数值,而不是用含义模糊的数来表示。
   c.枚举使代码更易于键入。
枚举定义:
public enum TimeOfDay
   {
     Morning = 0,
     Afternoon = 1,
     Evening = 2
   }
使用枚举:
switch(timeOfDay)
   {
      case TimeOfDay.Morning:
         Console.WriteLine("Good morning!");
         break;
      case TimeOfDay.Afternoon:
         Console.WriteLine("Good afternoon!");
         break;
      case TimeOfDay.Evening:
         Console.WriteLine("Good evening!");
         break;
      default:
         Console.WriteLine("Hello!");
         break;
   }


12.数组
一维数组:
  int[] numbers = new int[]{1,2,3,4,5};
   string[] names = {“张三”,”李四”,”王五”}
多维数组:
  int[,] numbers = new int[3,2]{{1,2}{3,4}{5,6}};
   string[,] names = {{“张三”,”李四”}{“王五”,”赵六”}}
数组的数组:
  int[][] numbers = new int[2][]{new int[]{2,3,4},new int[]{5,6,7,8,9}}

13.集合
a.IEnumerable和IEnumerator接口
  IEnumberable接口是大部分集合类型的根。
  它是一个支持foreach迭代的接口,一个集合对象要能遍历所有对象的话,那它必需要实现这个接口,它的声明结构如下:
  public interface IEnumerable
   {
    IEnumerator GetEnumerator ();
   }
  其中的GetEnumerator方法返回的是IEnumerator类型
  IEnumerator接口的声明如下:
public interface IEnumerator
   {
    //获取集合中的当前元素。
    Object Current { get; }
    //如果枚举成功推进到下一个元素,则为 true;如果枚举数越过集合的结尾,则为 false。
    bool MoveNext ();
    //将枚举数设置为其初始位置,该位置位于集合中第一个元素之前。
    void Reset () ;
   }
b.ICollection接口
  ICollection接口派生自IEnumerable接口,扩展了集合元素个数和同步功能(对多线程安全访问的支持)。
   ICollection接口的声明:
public interface ICollection : IEnumerable
   {
    //ICollection集合中元素的个数
    int Count { get; }
    //获取是否同步对ICollection 的访问
    bool IsSynchronized { get; }
    //获取用于同步ICollection访问的对象。
    Object SyncRoot { get; }
   }
   可以在对集合元素遍历的时候,把集合锁定,以防其它线程(用户)对集合的修改。
  ArrayList al = new ArrayList();
   al.Add("aaa");
   al.Add("bbb");
  lock (al.SyncRoot)
   {
    for(int i=0;i<al.Count;i++)
    {
     Console.WriteLine(obj);
    }
   }
c.IList接口
IList是一个值的集合,派生自ICollection,其成员可以通过索引访问。如ArrayList
  public interface IList : ICollection, IEnumerable
   {
    //将某项添加到IList集合中
   int Add(object value);
    //从 IList 中移除所有项。
   void Clear ();
    //确定 IList 是否包含特定值。
    bool Contains (Object value);
    //取得IList集合中指定项的索引号。
   int IndexOf (Object value);
    //将一个项插入IList集合的指定索引处。
   void Insert (int index,Object value);
    //从IList集合中移除指定的项对象。
   void Remove(object value);
    //从IList集合中移除指定索引项的对象。
   void RemoveAt(int index);
    //指示IList 是否具有固定大小。大小固定的集合在创建之后不允许添加或移除元素,但允许修改现有元素。
    bool IsFixedSize { get; }
    //IList 是否为只读。只读集合在创建之后不允许添加、移除或修改元素。
    bool IsReadOnly { get; }
    //获取或设置指定索引号元素的内容。可以使用此索引器实现集合元素的循环遍历。
   Object this [int index] { get; set; }
   }
d.IDictionary接口
IDictionary接口实现一个“键/值”对的集合,派生自ICollection,可以用循环遍历其中的每一个元素。其中的每个"键/值"对是一个DictionaryEntry 对象,只能用键名来存取对象,不能用索引号来存取对象。
  public interface IDictionary : ICollection, IEnumerable
   {
    //在IDictionary集合中添加键和值对元素。
   void Add (Object key,Object value);
    //从 IList 中移除所有项。
   void Clear ();
    //确定 IList 是否包含特定值。
   bool Contains (Object value);
    //返回一个用于 IDictionary 集合的 IDictionaryEnumerator 对象。
    IDictionaryEnumerator GetEnumerator ();
    //从集合中移除指定键值的元素
   void Remove (Object key);
    //指示IList 是否具有固定大小。大小固定的集合在创建之后不允许添加或移除元素,但允许修改现有元素。
    //IList 是否为只读。只读集合在创建之后不允许添加、移除或修改元素。
    bool IsFixedSize { get; }
    bool IsReadOnly { get; }
   Object this [Object key] { get; set; } //获取或设置具有指定键的元素。
   ICollection Keys { get; } //获取IDictionary中的所有的键集合。
    ICollection Values { get; } //获取IDictionary中的所有的值集合。
   }
e.ArrayList类
  ArrayList类实现了IList接口,用来存储非泛型对象。
Count属性:集合中实际元素的个数。
  Capacity属性:ArrayList空间的大小。生成一个ArrayList对象的时候默认分配了4个元素的空间(默认),在添加前4个元素的时候Capacity始终是4。当添加第5个元素的时候,首先框架会把ArrayList的Capacity的容量加倍,然后再把第5个元素存入。
   void AddRange (ICollection c):将一个新的ICollection对象加到当前ArrayList后面,通常用来拼接两个ArrayList。
   ArrayList GetRange (int index,int count):从当前的ArrayList对象中返回指定位置和指定数目的元素,并将这些元素以新的ArrayList对象形式返回。
   void InsertRange(int index,ICollection c) :在指定的位置插入另一个ICollection对象。
  void TrimToSize():将ArrayList的容量缩减到ArrayList的实际的元素个数。
void Reverse() :将数组的顺序进行返转。
  void Sort():将数组进行排序。
f.Hashtable类
  Hashtable实现了IDictionary接口,可以用来存储非泛型对象。由于Hashtable实现的是IEnumerable接口,所以可以用foreach对Hashtable进行遍历。
   void ContainsKey(object o)//判断Hashtable 是否包含指定键
   void ContainsValue(object o)//判断Hashtable是否包含指定的值。
   Hashtable Hashtable.Synchronized (Hashtable t) //静态方法,将一个普通的Hashtable包装为一个同步的(线程安全)Hashtable。
   如:
   Hashtable h = new Hashtable();
    h.Add("a","aaaa");
    h.Add("b", "bbbb");
   IEnumerator ie = h.GetEnumerator();
    while (ie.MoveNext())
    {
     Console.Write(((DictionaryEntry)ie.Current).Key + "/t" + ((DictionaryEntry)ie.Current).Value+"/n");
    }
g.Queue类和Stack类
   这两个类都实现了ICollection接口和IEnumerable接口,但没有实现IList接口。
Queue类:
   Queue:队列,先进先出。
    Enqueue(object var):入队
    object Dequeue() :出队
    object Peek():返回队首的元素,但不移除。出队和入队都分影响Queue对象的元素的个数,即影响其Count属性。

   Queue q = new Queue();
    q.Enqueue("aaa");
    q.Enqueue("bbb");
    q.Enqueue("ccc");
    for (int i = 0; i < 3; i++) //这里用的是i<3而不是i<q.Count,因为Dequeue的过程中会影响q.Count。
    {
     Console.WriteLine(q.Dequeue());
    }
  Stack类:
   Stack:堆栈,先进后出。
    Push(object var): //进栈
    object Pop() : //出栈
    object Peek(): //返回栈顶元素,但不移除入栈和出栈都会影响Stack的元素个数。
   Stack s = new Stack();
    s.Push("aaa");
    s.Push("bbb");
    s.Push("ccc");
    for (int i = 0; i < 3; i++) //这里用的是i<3而不是i<s.Count,因为Pop的过程中会影响s.Count。
    {
     Console.WriteLine(s.Peek());
    }
h.NamueCollection类
   类似于有序的字符串值和字符串键的集合,它并没实现IDictionary接口。
  string[] AllKeys属性:所有键的字符串数组。
   bool HasKeys():集合对象中是否包含"键/值"对。
   string Get(int index/string key):根据索引号或键名来取得元素的值。
   string GetKey(int index):根据索引号取得键名。
   对NamueCollection集合对象的遍历:
  NamueCollection nvc = new NamueCollection();
   nvc.Add("a", "aaa");
   nvc.Add("b","bbb");
   nvc.Add("c","ccc");
   foreach (string s in nvc.AllKeys)
   {
    Console.WriteLine(nvc[s].ToString());
   }
  
14.拆箱装箱
拆箱:把数据由引用类型变换为值类型。把数据由堆空间转换到栈空间。
装箱:把数据由值类型变换为引用类型。把数据由栈空间转换为堆空间。
装箱:
   int I = 10;
   object o = (object)I;
拆箱:
   object 0 = 10;
   int I = (int)o;

15.流程控制
条件语句
   if (条件)
   {
      statement(s)
   }
   else if(条件)
   {
    statement(s)
   }
   else
   {
      statement(s)
   }
   添加到if子句中的else if语句的个数没有限制
switch语句
   switch...case语句适合于从一组互斥的分支中选择一个执行分支。它只对一个个离散的常量值进行分支判,而if...else if...else可以对连续的区间进行判断
   switch (integerA)
   {
     case 1:
        Console.WriteLine("integerA =1");
        break;
     case 2:
        Console.WriteLine("integerA =2");
        break;
     case 3:
        Console.WriteLine("integerA =3");
        break;
     default:
        Console.WriteLine("integerA is not 1,2, or 3");
        break;
   }
   注意case的值必须是常量表达式——不允许使用变量。
for循环
   for (initializer; condition; iterator)
   {
    statement(s)
   }
while循环
   while(condition)
   {
   statement(s);
   }
foreach循环
   foreach循环可以迭代集合中的每个项目。foreach循环一次迭代数组中的一个元素。
   foreach (int temp in arrayOfInts)
   {
    statement(s)
   }
break语句
   break也可以用于退出for、foreach、while或do...while循环,循环结束后,立即执行后面的语句。
continue语句
   用于for、foreach、while或 do...while循环中。但它只从循环的当前迭代中退出,然后在循环的下一次迭代开始重新执行,而不是退出循环。
return语句
   return语句用于退出类的方法,把控制返回方法的调用者,如果方法有返回类型,return语句必须返回这个类型的值,如果方法没有返回类型,应使用没有表达式的return语句。

16.运算符:

 


is运算符
is运算符可以检查对象是否与特定的类型兼容。例如,要检查变量是否与object类型兼容:
   “兼容”是指对象是该类型,或者派生于该类型。
int i = 10;
   if (i is object)
   {
     Console.WriteLine("i is an object");
   }
as运算符
  as运算符用于执行引用类型的显式类型转换。如果要转换的类型与指定的类型兼容,转换就会成功进行;如果类型不兼容,as运算符就会返回值null。
  object o1 = "Some String";
   object o2 = 5;
   string s1 = o1 as string;      //s1 = "Some String"
   string s2 = o2 as string;     //s1 = null
typeof运算符
   Typeof运算符返回一个表示特定类型的Type对象。例如,typeof(string)返回表示System.String类型的Type对象。在使用反射动态查找对象的信息时,这个运算符是很有效的。

 


17.类型转换
隐式转换,显示转换

类和结构
类和结构实际上都是创建对象的模板,每个对象都包含数据,并提供了处理和访问数据的方法。
类是存储在堆(heap)上的引用类型,而结构是存储在堆栈(stack)上的值类型。较小的数据类型使用结构可提高性能。但在语法上,结构与类非常相似,主要的区别是使用关键字struct代替class来声明结构。在大多数情况下,类要比结构常用得多。
类:
  class PhoneCustomer
   {
    public const string DayOfSendingBill ="Monday";
   public int CustomerID;
    public string FirstName;
    public string LastName;
   }
结构:
  struct PhoneCustomerStruct
   {
     public const string DayOfSendingBill = "Monday";
     public int CustomerID;
     public string FirstName;
     public string LastName;
   }
对于类和结构,都使用关键字new来声明实例:这个关键字创建对象并对其进行初始化。
PhoneCustomer myCustomer = new PhoneCustomer();     //works for a class
PhoneCustomerStruct myCustomer2 = new PhoneCustomerStruct();   // works for a struct

一.类的封装:
1.数据成员: 字段、常量和事件。
   数据成员可以是静态数据或实例数据。不做特殊说明时,类成员总是实例成员,除非用static进行了显式的声明。
   静态成员属于类的,在所有的对象中都使用一个存储空间
   实例成员属于对象的,在每一个对象中都使用一个独立的存储空间
2.函数成员:函数成员提供了操作类中数据的某些功能,包括方法、属性、构造函数和终结器(finalizor)、运算符以及索引器。
  (1)方法
    a.方法的声明
     [modifiers] return_type MethodName([parameters])
     {
       // Method body
     }
     如果方法没有返回值,就把返回类型指定为void,因为不能省略返回类型。
    b.调用方法
     函数名(实参列表);
    c.给方法传递参数
    ref关键字:迫使值参数通过引用传送给方法。如果把一个参数传递给方法,且这个方法的输入参数前带有ref关键字,则该方法对变量所作的任何改变都会影响原来对象的值。
      在调用该方法时,还需要添加ref关键字:
     SomeFunction(ints, ref i);
    out关键字:使函数能从函数内向函数外输出多个值。当在方法的输入参数前面加上out关键字时,传递给该方法的变量可以不被初始值初始化。
      在调用该方法时,还需要添加out关键字:
     SomeFunction(out i);
    方法的重载:方法名相同,但参数个数与参数类型不同。不能够根据方法的返回值形成重载。
    
(2)属性
    用来给成员变量赋值与取值的功能。
    private string foreName;
    public string ForeName
    {
      get
      {
         return foreName;
      }
      set
      {
         if (value.Length > 20)
            // code here to take error recovery action
            // (eg. throw an exception)
         else
            foreName = value;
      }
    }
    只有get部分的属性称为只读属性,只有set部分的属性称为只写属性
   不能在get或set之间加访问修饰符
  (3).构造函数
    如果没有显式地提供任何构造函数,编译器会在后台创建一个默认的构造函数。
    构造函数没有返回类型,且函数名与类名同名。
    构造函数可以形成重载。
   
   静态构造函数:可以给类编写无参数的静态构造函数这种构造函数只执行一次,而前面的构造函数是实例构造函数,只要创建类的对象,它都会执行。类有一些静态字段或属性,需要在第一次使用类之前,从外部源中初始化这些静态字段和属性。
     注意:
     静态构造函数没有定义访问修饰符总是由.NET运行库调用它,所以像public 和 private这样的访问修饰符就没有意义了。
     静态构造函数不能带有任何参数
     一个类也只能有一个静态构造函数
     静态构造函数只能访问类的静态成员,不能访问实例成员。
      无参数的实例构造函数可以在类中与静态构造函数安全共存。尽管参数列表是相同的,但这并不矛盾。因为静态构造函数是在加载类时执行,而实例构造函数是在创建实例时执行。
      如果多个类都有静态构造函数,先执行哪个静态构造函数是不确定的。

    从其他构造函数中调用构造函数:
    class Car
     {
       private string description;
       private uint nWheels;
       public Car(string model, uint nWheels)
       {
          this.description = description;
          this.nWheels = nWheels;
       }
       public Car(string model) : this(model, 4)//构造函数初始化器
       {
       }
     }

     在本例中,在带有一个参数的构造函数执行之前,先执行带2个参数的构造函数
    
   (4)只读字段
    只读字段readonly类似于const常量,但与常量又有所不同。const常量在定义的时候就必须对它进行赋初值,在以后的使用过程中是不许进行改变的,而readonly形的变量在定义的时候可以不赋值,而在构造函数中对它进行初始化值,一旦赋值后就不可再更改其值,它类似于java中的final型的变量。
    readonly关键字比const灵活得多,允许把一个字段设置为常量,但在将字段设为常量之前可以执行一些运算,以指定它的初始值。
   在构造函数中给readonly字段赋值,但不能在其他地方赋值
    readonly字段还可以是一个实例字段,而不是静态字段,类的每个实例可以有不同的值
   如果要把readonly字段设置为静态,就必须使用static关键字进行显式声明;
    在构造函数中未给readonly 字段赋值,它的值就是其数据类型的默认值
   public class Document
    {
        public readonly DateTime CreationDate;
        public Document()
        {
           CreationDate = new DateTime(2002, 1, 1);
        }
    }

二、类的继承
C#不支持多重实现继承。而C#却允许类型派生于多个接口。因为System.Object是一个公共的基类,所以每个C#类(除了Object类之外)都有一个基类,还可以有任意多个基接口。

(1)类的继承语法:
  class MyDerivedClass : MyBaseClass
   {
     // functions and data members here
   }
(2)虚方法
   把一个基类函数声明为virtual,该函数就可以在任何派生类中重写了,否则默认基类中的函数是无法被重写的。也可以把属性声明为virtual。
  class MyBaseClass
   {
     public virtual string VirtualMethod()
     {
        return "This method is virtual and defined in MyBaseClass";
     }
     public virtual string ForeName
    {
      get { return foreName; }
      set { foreName = value; }
    }
   private string foreName;
   }

   在C#中,函数在默认情况下不是虚拟的,但(除了构造函数以外)可以显式地声明为虚拟。而在Java中,所有的函数都是虚拟的。
  在派生类的函数重写另一个函数时,要使用override关键字显式声明:
   class MyDerivedClass : MyBaseClass
   {
    
public override string VirtualMethod()
     {
        return "This method is an override defined in MyDerivedClass";
     }
   }

(3)隐藏方法
   如果签名相同的方法在基类和派生类中都进行了声明,但该方法没有声明为virtual 和 override,派生类方法就会隐藏基类方法。
   成员字段和静态函数都不能被声明为virtual,因为这个概念只对类中的实例函数成员有意义。
   如果签名相同的方法在基类和派生类中都进行了声明,但该方法没有声明为virtual 和 override,派生类方法就会隐藏基类方法。结果是调用哪个类的方法取决于用于引用实例的变量类型,而不是实例本身的类型。
   系统会发出警告。在C#中,应使用new关键字声明我们要隐藏一个方法。
(4)调用函数的基础版本
   从派生类中调用方法的基础版本:base.<MethodName>()。
   class CustomerAccount
   {
     public virtual decimal CalculatePrice()
     {
        // implementation
       return 0.0M;
     }
   }  
   class GoldAccount : CustomerAccount
   {
     public override decimal CalculatePrice()
     {
        return base.CalculatePrice() * 0.9M;
     }
   }
   可以使用base.<MethodName>()语法调用基类中的任何方法,不必是在同一个方法的重载中调用它。
(5)抽象类和抽象函数
   抽象类不能实例化,而抽象函数没有执行代码,必须在非抽象的派生类中重写。
   如果类包含抽象函数,该类将也是抽象的,也必须声明为抽象的:
   abstract class Building
   {
     public abstract decimal CalculateHeatingCost();   // abstract method
   }

(6)密封类和密封方法
   把类和方法声明为sealed,对于类来说,这表示不能继承该类,对于方法来说;这表示不能重写该方法。
   类似于Java中的final。

   sealed class FinalClass
   {
     // etc
   }
   class DerivedClass : FinalClass       // 错误:密封类无法被继承
   {
     // etc
   }
   在方法上使用sealed关键字是没有意义的,如果定义一个新方法,但不想让别人重写它,不要把它声明为virtual就可以了。

(7)派生类的构造函数(车延禄)
   基类的构造函数总是最先调用。也就是说,派生类的构造函数可以在执行过程中调用基类方法、属性和其他成员,因为基类已经构造出来的,其字段也初始化了。
a.无参数的构造函数
   b.有参数的构造函数
    使用在子类构造函数之后使用base关键字调用父类构造函数,并传递构造实参

三、可见性修饰符


不能把类型定义为protected、internal和protected internal,这些修饰符只能应用于成员。
四、其他修饰符


五、接口
接口中只能包含方法、属性、索引器和事件的声明。
不能实例化接口,接口不能有构造函数或字段

在接口定义中还不允许声明成员上的修饰符。接口成员总是公共的,不能声明为虚拟或静态。
1.定义和实现接口
    public interface IBankAccount
     {
       void PayIn(decimal amount);
       bool Withdraw(decimal amount);
       decimal Balance
       {
          get;
       }
     }
    接口名称传统上以字母I开头,以便知道这是一个接口。(车延禄)

2.接口的派生
   public interface ITransferBankAccount : IBankAccount
    {
       bool TransferTo(IBankAccount destination, decimal amount);
    }

六、结构
类在实例化过程中会在堆中创建对象,但性能会有一定的损失。有时仅需要一个小的数据结构,为了实现性能的优化我们可以使用结构替代类。
结构是值类型,不是引用类型。它们存储在堆栈中。
结构不支持继承。
结构中可以有方法。
结构有构造函数,编译器总是提供一个无参数的默认构造函数,这是不允许替换的。
结构可以实现接口


结构定义
struct Dimensions
{
     public double Length;
     public double Width;
     Dimensions(double length, double width)
     { Length= length; Width= width; }
     public int Diagonal
     {
        {
           get
           {
              return Math.Sqrt(Length* Length + Width* Width);
           }
        }
      }
}
使用结构
Dimensions point = new Dimensions();
point.Length = 3;
point.Width = 6;

因为结构是值类型,所以new运算符与类和其他引用类型的工作方式不同。new运算符并不分配堆中的内存,而是调用相应的构造函数,根据传送给它的参数,初始化所有的字段

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值