07 C#之 深刻理解类

1.类成员

类成员分数据成员和函数成员,数据成员用于保存数据,函数成员用于执行代码。


类成员类型:字符,方法,运算符,常量,属性,索引,构造函数,析构函数,事件 

2. 成员修饰符

[特性] [修饰符] 核心声明

特性:如果有特性,必须放在修饰符和核心声明之前;如果有多个特性,可任意顺序

修饰符:如果有修饰符,必须放在核心声明前;如果有多个修饰符,可任意顺序

static private int TestCount = 10;

private static int TestCount = 10; 这2中声明式等效的。

3. 实例成员

类成员可以关联到类的一个实例。类的每个实例拥有自己的各个类成员的副本—实例成员。改变一个实例字段的值不会影响任何其它实例中成员的值。

class MyDemoClass

    {

        public int TestValue;

    }

class Program

    {

        static void Main(string[] args)

        {

            MyDemoClass d1 = new MyDemoClass();

            d1.TestValue = 123;

            MyDemoClass d2 = new MyDemoClass();

            d2.TestValue = 456;

            Console.WriteLine($"d1 value:{d1.TestValue}, d2 value:{d2.TestValue}");

        }

    }

输出:

d1 value:123, d2 value:456

实例变量至于对应的实例关联 ,类的实例都有自己字段的副本。


堆上分配的内存

4. 静态字段

静态字段被类的所有实例共享,所有实例都访问同一内存位置。

使用static 修饰符将字段声明为静态

class MyDemoClass

    {

        public int TestValue;//实例字段

        public static int StaticValue=999;//静态字段

    }

5. 从类的外部访问静态成员

类名+点+成员名称 (MyDemoClass.StaticValue)

静态成员的生存周期

与实例成员不同,实例成员只有实例创建后才产生,实例销毁后实例成员就不存在了。

静态成员,即使没有实例,也存在,并可以访问。

6. 静态函数成员

静态函数成员也是独立于任何类实例的,即使没有实例,仍可以调用静态方法。

静态函数不能访问实例成员,但能访问其它静态成员。

class Demo

    {

        static public int x;// 静态字段

        static public void PrintX()//静态方法

        {

            Console.WriteLine($"Value of X:{x}");

        }

    }

测试:

class Program

    {

        static void Main(string[] args)

        {

            Demo.x = 66;//使用句点语法

            Demo.PrintX();//使用句点语法

        }

    }

7. 其它静态类成员类型

可声明为静态的类成员类型


8. 成员常量

成员常量类似本地常量,只是它被声明在类中,而不是在方法内。

初始化成员常量的值在编译时必须是可计算的,而且通常是一个预定义简单类型或者他们组成的表达式。

在类中声明:

const int Val = 100;// 定义int 类型常量,初始值100

与C,C++不同,在C#中没有全局常量,每个常量都必须声明在类中。

const int IntVal;// 错误,必须初始化

IntVal=100;//错误,不允许赋值

9. 常量与静态量

成员常量:表现想静态只,但不能使用 static声明。与静态常量不同,没有自己的存储位置,而是编译时被编译器替换。

静态常量

public const double PI = 3.1415;// 常量

使用:类名.PI

10. 属性

属性是代表类的实例或者类中的一个数据项的成员。

属性与字段类型,有如下特征:

它是命名的类成员

它有类型

它可以被赋值和读取


然而字段只属于一个函数成员,它不为数据存储分配内存空间

属性是指定的一组2个匹配的,访问器的方法:

set访问器为属性赋值,get访问器从属性取值。

属性声明和访问器

class Demo

    {

        private int FiledValue;//字段,分配内存(后备字段)

        public int MyValue //属性,未分配内存

        {

            set { FiledValue = value; }

            get { return FiledValue; }

        }

    }

使用属性

Demo d = new Demo();

d.MyValue = 20;//Set 赋值

Console.WriteLine($"{d.MyValue}");

属性和关联字段

常见的方式是在类中将字段声明为private以封装字段,并声明一个public熟悉控制从类外部对该字段的访问。

和熟悉关联的字段常被称作后备字段或后备存储。

属性定义的2中常见方式,使用Pascal大小写,Camel大小写版本

private string name;

public string Name

{

     get { return name; }

    set { name = value; }

}

private string _name;

 public string Name

  {

     get { return _name; }

     set { _name = value; }

 }

执行其它计算

访问器get,set  能执行任何计算,也可以不执行任何计算,唯一需求行为是get访问器需要返回一个属性类型的值。

public int MyValue

  {

            set { }//什么也不设置

            get { return 100; }//只是返回100

   }

  private int _myValue2;

 public int MyValue2

 {

         get { return _myValue2; }

         set

          {

                MyValue2 = value > 100 ? 100 : value;//条件运算

            }

    }

C# 7.0引入了另一种语法,表达式函数体(Lambda表示)

private int score;

 private int Score

{

       set => score>100?100 : value;

      get => score;

}

只读和只写属性

只有get 访问器的属性称为只读属性

只有set访问器的属性称为只写属性(很少见,几乎没有实际用途)

两个访问器中至少有一个必须定义,否则编译器产生错误。

属性与共有字段

属性是函数成员,而不是数据成员,允许输入输出。

属性可以是只读或只写,字段不可以。

编译后的变量和编译后的属性语义不同。

自动实现属性

只声明属性,不声明后备字段。编译器自动创建隐藏后备字段。

public string lastName { get; set; }

静态属性

属性声明为static,和静态成员一样:

不能访问类的实例成员,但能被实例成员访问。

不管类是否有实例,它们都是存在的。

在类的内部,可以仅使用名称来引用静态属性。

class Test

    {

        public static int MyValue { get; set; }

        public void PrintValue()

        {

            Console.WriteLine($"Value from inside:{MyValue}");// 类的内部访问

        }

测试:

//类的外部访问

 Console.WriteLine($"Initial Value:{Test.MyValue}");

Test.MyValue = 20;

Console.WriteLine($"New Value:{Test.MyValue}");

11. 实例构造函数

实例构造函数是一个特殊的方法,它在创建类的每个新实例时执行。

构造函数用于初始化类实例的状态

如果需要从类的外部创建类的实例,需要声明为public

构造函数的名称和类同名

构造函数不能有返回值

带参数的构造函数

构造函数可以带参数

构造函数可以被重装

public class Demo

    {

        int id;

        string name;

        public Demo() { id = 1; name = "name1"; }// 无参构造函数

        public Demo(int ID) { id = ID; name = "testName2"; }//带一个参数的构造函数

        public Demo(int Id,string Name) { id = Id; name = Name; }//带2个参数的构造函数

        public void ShowMessage()

        {

            Console.WriteLine($"Name:{name}, Id:{id}");

        }

    }

测试上演示类:

class Program

    {

        static void Main(string[] args)

        {

            Demo d1 = new Demo();

            d1.ShowMessage();

            Demo d2 = new Demo(123);

            d2.ShowMessage();

            Demo d3 = new Demo(456, "MyName");

            d3.ShowMessage();

        }

    }

默认构造函数

没有参数;方法体为空

如果类声明了任何构造函数,编译器就不会创建默认的构造函数。

静态构造函数

构造函数也可以声明为static,实例构造函数初始化类的每个实例,而静态构造函数初始化类级别的项。通常静态构造函数初始化类的静态字段。

类只能有且只能有一个构造函数,且不能带有参数,静态构造函数不能有访问修饰符。


类即可有静态构造函数,也可以有实例构造函数。

静态构造函数不能访问任何实例成员,因此也不能使用this访问器

不能从程序中显示调用静态构造函数,系统会自动调用它们。

class RandomNumber

    {

        private static Random RandomKey;//私有静态变量

        static RandomNumber() // 静态构造函数

        {

            RandomKey = new Random();

        }

        public int GetRandKeyNumbers()

        {

            return RandomKey.Next();

        }

    }

测试调用:

class Program

    {

        static void Main(string[] args)

        {

            RandomNumber rndN1 = new RandomNumber();

            RandomNumber rndN2 = new RandomNumber();

            Console.WriteLine($"Next Random #{rndN1.GetRandKeyNumbers()}");

            Console.WriteLine($"Next Random #{rndN2.GetRandKeyNumbers()}");

        }

    }

输出:

Next Random #365872672

Next Random #1403081881

对象初始化语句

new TypeName {Field1=InitExpr1, Filed2=InitExpr2} //对象初始化语句

new TypeName(ArgList) {Field1=InitExpr1, Filed2=InitExpr2} //成员初始化语句

析构函数

析构函数destructor 执行的类在实例被销毁之前需要的清理或释放非托管资源的行为。

readonly 修饰符

const字段只能在字段的声明语句中初始化,而readonly字段可在如下任意位置设置:

字段声明语句

类的任何构造函数

const字段的值必须可在编译时决定,而readonly字段的值可在运行时决定。

const的行为总时静态的,对于readonly字段可以是静态字段,也可是实例字段,在内存中有存储位置。

readonly double PI=3.1415;

12. This 关键字

对当前实例的引用,只能被用在下列类成员的代码块中:

实例构造函数

实例方法

属性和索引器的实例访问

所以不能在任何静态函数成员的代码中使用。


使用this的目的:

用于区分类的成员和局部变量或参数。

作为调用方法的实参。

13. 索引器

什么是索引器:索引器是一组get和set访问器,与属性类似。

索引器和属性:

索引器和属性一样不用分配内存来存储

索引器和属性都主要被用来访问其它数据成员。

属性通常表示单个数据成员,索引器通常表示多个数据成员。

声明索引器:

索引器没有名称。在名称的位置是关键字this。参数列表在方括号中间;参数列表中必须至少声明一个参数。

ReturnType  this[Type param,...]

{

    get {...}

    set {...}

}

索引器的set 访问器

当索引器被用于赋值时,set访问器被调用。

索引器的get 访问器

当索引器获取值时,可以通过一个或多个参数调用get访问器。

不能显示调用get,set访问器。

class Employee

    {

        public string FirstName;

        public string LastName;

        public string CityOfBirth;

        //以上代码是没有索引的简单类

        //声明一个索引器

        public string this[int index]

        {

            set

            {

                switch (index)

                {

                    case 0:

                        FirstName = value;

                        break;

                    case 1:

                        LastName = value;

                        break;

                    case 2:

                        CityOfBirth = value;

                        break;

                    default:

                        throw new ArgumentOutOfRangeException("index");

                }

            }

            get

            {

                switch (index)

                {

                    case 0:

                        return FirstName;

                    case 1: return LastName;

                    case 2: return CityOfBirth;

                    default:

                        throw new ArgumentOutOfRangeException("index");

                }

            }

        }

    }

测试代码:

class Program

    {

        static void Main(string[] args)

        {

            Employee ep = new Employee();

            ep.FirstName = "Jane";

            ep.LastName = "Doe";

            ep.CityOfBirth = "Dallas";

            Console.WriteLine($"{ep.LastName} {ep.FirstName} {ep.CityOfBirth}");

            // 使用索引器

            Console.WriteLine($"{ep[0]} {ep[1]} {ep[2]}");

        }

    }

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容

  • 类是一个重要的C#编程概念,它在一个单元内定义了表示和行为。类提供了面向对象编程和面向组件编程所需的语言支持,是创...
    CarlDonitz阅读 806评论 0 2
  • 一、类型C#是一种类型安全的静态语言。这要求创建任何变量时,都必须将其数据类型告知编译器;编译器将确保只能将兼容的...
    CarlDonitz阅读 396评论 0 1
  • 深入理解C# 静态类与非静态类、静态成员的区别静态类 静态类与非静态类的重要区别在于静态类不能实例化,也就是说,不...
    好怕怕阅读 1,413评论 0 1
  • .NET FrameWork框架 类似于JVM,由两个重要组件组成:CLR公共语言运行时;统一的.NET类库集。类...
    FTD止水阅读 1,001评论 0 0
  • 1. c# 运行过程 2. 源代码执行过程 源代码------->编译--------->执行 1). 编译阶段 ...
    Louis_yi阅读 157评论 0 0