第四章:定义封装的类类型

Posted zhangliangliang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第四章:定义封装的类类型相关的知识,希望对你有一定的参考价值。

     就.NET平台而言,最基本的编程结构就是类类型。

     类是由字段数据(通常叫做成员变量)以及操作这个数据的成员(构造函数,熟悉,方法,事件等)所构成的自定义类型。

    注:类中的字段很少定义为公共(public)的,为了保护状态数据的完整性,最好将数据定义为私有(private)的或是受保护(protected)的. 

  public class CDome
{
public int id; private int code; protected int pCode; public CDome(){} public CDome(int MyId) { id=MyId; } public void Say(string text) { MessageBox.show(text); }
}

 

Class: 定义类的关键字。
public:类的访问范围
Cdome:类的名字
public CDome():类的构造函数

1.使用new关键字来分配对象

    对象必须使用new关键字来分配到内存中。如果我们不使用new关键字,兵器在代码中尝试使用变量的话,就会收到编译器错误。

    定义分配对象:CDome dome = new CDome();

    定义和分配对象分开编写代码:

    CDome dome;//只是声明了指向尚未被创建的CDome对象的引用。

    dome=new CDome();//通过new 关键字把引用赋给对象后,这个引用才会指向内存中的有效类实例。

2.构造函数


public CDome(){}
public CDome(int MyId)
{
     id=MyId;
}

 

   构造函数,它允许在创建对象时创建其状态。它是类的特殊方法,在使用new关键字创建对象时被间接调用。

   特点:构造函数永远不会返回值,且他的名字必须和需要构造的类的名字相同  【public CDome(){}

  默认构造(无参构造):

     1).把新对象分配到内存中,取保所有字段数据都设置为正确的默认值。·

     2).在new类对象时,如果调用了有参构造,那么默认构造就失效了。 CDome dome= new CDome("测试");

自定义构造(有参构造):

    让构造函数彼此不同的是构造函数的参数个数和类型。

 3.this关键字

    1).this关键字解决当传入参数的名字和类型数据字段名字相同时产生的作用域歧义。

1 public class Say
2 {
3    ppublic int name="";
4   public Say(string name)
5   {
6      this.name=name; 
7   }
8 }

   2).this关键字会启用只能感应,这样有助于我们快速回忆忘掉的类成员名称以及提高编写代码效率。

   3).在静态成员的实现中用this关键字,会产生编译器错误,原因:静态成员在类(不是在对象)级别产生作用,一次在类级别没有当前对象(也就没有this).

   3).this关键字其中的一个用法是使用一项名为构造函数链的技术来设计类(当定义了多个构造函数时,这个设计模式就会很有用)。

 1 //代码
 2 public class Say
 3 {
 4   public string name;
 5   public string id;
 6   public Say(){}
 7   public Say(string name){this.name=name;}
 8   public Say(string name,string id){this.name=name;this.id=id;}
 9 }
10 //改为串联构造函数
11 public class Say
12 {
13   public string name;
14   public string id;
15   public Say(){}
16   public Say(string name):this(name,"")
17 {
18 Console.WriteLine("构造函数逻辑流程(4)");
19 }
20 public Say(string name,string id){this.name=name;this.id=id;}//住构造函数 21 }

 4).构造函数逻辑流程

     (1).通过调用只有单个int的构造函数来创建对象。

     (2).构造函数将提供的数据转发给主构造函数,并且提供调用者没有提供的其他出事参数。

     (3).主构造函数把传入的数据赋值给对象的字段数据。

     (4).控制返回到最初调用的构造函数,并且执行所有剩余的代码语句

5).使用构造函数链的好处是,这种变成模式在任何版本的c#语言和.net平台中都可用的。然而,在使用net4或者更高版本时,你还可以是哟娜可选参数代替传统的函数链,从而大大简化编程任务。

    注:可选参数只能在vs2010,.net4及以上版本使用。

 //代码
  public class Say
 {
  public string name;
   public string id;
   public Say(string name,string id=""){this.name=name;this.id=id;}
 }

 4.static关键字

   C#类(或结构)可以通过static关键字来定义静态成员,这些成员只能通过类级别调用。 

   静态成员只能操作静态数据或调用类的静态方法,如果在静态成员中使用非静态类数据或调用类非静态方法,就会受到编译时错误。

   静态变量分配一次值,被类的所有实例所共享。

public class Say
{
   public static name="张三"//静态变量
public static Say()//静态构造函数
{
name="李四";
   }
public static void ToSay()//静态方法 { Console.WriteLine(name); } }

 静态构造函数:特殊的构造函数,非常适用于初始化在编译时为止的静态数据值。

   1).一个类只可以定义一个静态构造函数。

   2).静态构造函数不允许访问修饰符,不能接受任何参数。

   3).无论创建了多少类型的对象,静态构造函数只能执行一次。

   4).运行库创建类实例或调用者首次访问静态成员之前,运行库会调用静态构造函数。

   5).静态构造函数的执行先于任何实例级别的构造函数。

 静态类:用static 修饰的类为静态类。静态类不能使用new关键字来创建,且类里只能包含用static关键字标记的成员或字段。

public static class Say
{
   public static name="张三"//静态变量
   public static Say()//静态构造函数
   {
       name="李四";
   }

   public static void ToSay()//静态方法
    {
       Console.WriteLine(name);   
    }
}
//类调用:类名.方法
Say.ToSay();

 5.OOP的支柱

    所有基于对象的语言(C#,JAVA,C++,Smalltalk 和 VisualBasic等)必须满足OOP的3个核心原则,通常也叫做“OOP的支柱”:封装、继承、多态。

    封装:将用户不必了解的实现细节隐藏起来的一种语言能力。

    继承:基于已有的类定义来创建新类定义的语言能力。

    多态:语言以同一种方式处理相关对象的能力。

6.C#访问修饰符

   类型:类、接口、结构、枚举、委托

 成员:属性、方法、构造、字段

访问修饰符

可以应用到的地方

作用

public

类型或者类型成员

公共的项没有限制。公共成员可从对象以及任何派生类访问。

公共类型可以从其他外部程序集进行访问。

private

类型成员或嵌套类型

私有项只能由定义它们的类(或结构)进行访问。

protected

类型成员或嵌套类型

受保护项可以由定义他们的类以其任意子类使用,但外部类无法通过c#的点操作符访问。

internal

类型或类型成员

内部项只能在当前程序集中访问。如果我们在.net类库中定义一组内部类型的话,其他程序及就不能使用他们

Protected internal

类型或嵌套类型

如果在一个项上组合protected internal 关键字,项在定义他们的程序集、类以及派生类中可用。

 

 1).默认情况下,类型成员是隐式私有的,类型是隐式内部的。

class Say//默认内部
{
   Say(){}//默认私有
}

2).嵌套类型:直接声明在类或结构作用域中的类型。

public class Say 
{
    private enum MyColor//嵌套类型
    { 
       Red,Green,Blue
    }

 7.封装

    封装概念核心:对象的内部数据不应该从对象实例直接访问,如果调用者想改变对象的状态,就要使用访问方法(即getter)和修改方法(即setter).

   黑盒编程:英文名称:black box programming。   对外部世界隐藏操作数据方式的细节。

   使用传统的访问方法和修改方法:

public class Say 
{
    private string name="";
    public Say(string name)
    {
         this.name=name;//修改方法
    }
    public string GetName()//访问提取name
   {
       return name;
   }
}

使用.NET属性进行封装 (value 表示调用者设置属性时传入的值,该标记不是c#关键字,而是上下文关键字)

public class Say 
{
    private string name="";
    public string Name
    {
        get{retrun name;}//获取(访问方法)
        set{name=value;}//设置(修改方法)
    }
}

 静态属性

public class Say 
{
    private static string name="";
    public static string Name
    {
        get{retrun name;}//获取(访问方法)
        set{name=value;}//设置(修改方法)
    }
}

8.自动属性

在.NET3.5发布的时候,c#语言提供了另外一种使用最少的代码定义简单封装服务的方法,叫做自动属性语法。

 自动属性不允许构建只读或只写的自动属性。

自动属性交互:直接调用属性名称(编译时才会定义私有的返回字段)

public class Say 
{
       //自动属性:在类中调用直接调用属性名称
       public  string Name{get;set;}
}

9.对象初始化器语法

     对象初始化语法只是使用默认构造函数创建类变量并设置各个属性状态数据的语法的简写形式。

public class Say 
{
    public Say(string value,string text)
    {
    }
}
//对象初始化器语法调用
Say sShow = new Say{value="1",text="张三"}

 初始化内部类型

public class Say 
{
   private Point topLeft =new Point();
    public Point TopLeft
    {
        get{retrurn topLeft;}
        set{topLeft=value;}
    }
    public Say(string value,string text)
    {
    }
}
//对象初始化器语法调用 TopLeft内部类型
Say sShow = new Say{TopLeft=new Point{X=10,Y=10},value="1",text="张三"}

 

10.常量数据(关键字 const)

  1).定义常量时必须指定值。

  2).常量在调用时不能改变值(只能在定义时赋值)

  3).常量是隐式静态的。

  4).只读字段:只读字段的值可以在运行时决定,因此在构造函数作用域中进行赋值是合法的。

public class Say 
{
    public const double id=3.14;//常量(其他地方不能改变值)
    public readonly double readId;//只读字段
public static readonly double readsId=3.14;//静态只读字段: 如果运行时才知道静态只读字段的值,就必须用静态构造函数
public Say() { readId=3.14;//可以在构造函数中为制度字段赋值,其他地方不行 }
public static Say(){readsId=3.14}//静态构造函数 }

 11.分部类型和分部方法(引用(风尘浪子):https://www.cnblogs.com/leslies2/archive/2011/09/09/2172267.html

在面向对象的“封装闭合性”开发原则中,一向提倡的是把独立的功能封装在一个类里面的!但从Visual Studio 2005开发,系统提供了一个分部类的开发方式一直受到争议,很多人认为把同一类的功能分布不同的文件中,是打破了“封装闭合原则”,一个类的功能变得难以管理,大多数人都是在无奈的情况下才使用到分部类的方式。但在winFrom类、页面类、DataSet里面你经常可以发现分部类的身影,当你用到Entity Framework的时候,你会发现每个映射生成的对象都是使用分部类的方式生成的,分部类似乎早已派上用场。分部类究竟有什么好处,下面为大家一一揭露。

1.分部类

根据微软的定义,分部类就是“将类或结构、接口或方法的定义拆分到两个或多个源文件中。 每个源文件包含类型或方法定义的一部分,编译应用程序时将把所有部分组合起来”。在使用分部类的时候,必须为类加入partial的关键字,注意每个类的可访问性必须一致,其中一类为public,其他类也必须为public。如果其中一个类为抽象类,那合并后整个类都将被视为抽象类,其中一个类为密封类,那合并后整个类都将视为密封类。

技术分享图片
 1 publicpartialclass PersonManager
2 {
3 public Person GetPersonById(int id)
4 {
5 }
6 }
7
8 publicpartialclass PersonManager
9 {
10 public List<Person> GetList()
11 {
12 }
13 }
技术分享图片

在合并的时候,总体类全把所有的基类和特性合并继承。要注意的是分部类必须在于同一个程序集当中,而且关键字不得相冲,如果一个类上为public ,另一个类为private,那将会出错。在第二个分部类中可以调用第一个分部类中所定义的字段与方法。

技术分享图片
 1 [SerializableAttribute]
2 public partialclass Person { }
3
4 [ObsoleteAttribute]
5 public partialclass Person { }
6
7 //合并后相当于
8 [SerializableAttribute]
9 [ObsoleteAttribute]
10 class Person{ }
11
12
13 partialclass PersonManager:Manager{ }
14
15 partialclass PersonManager:Collection{ }
16
17 //合并后相当于
18 class PersonManager:Manager,Collection{ }
技术分享图片

 

2).分部方法

分部方法与分部类十分相像,方法必须包含partial关键字,如果一个类中并不包含该方法的实现,而另一个类中实现了该方法,将不会影响这个方法的正常运行。这个特点跟接口有异曲同工之妙,特别是在使用代码生成器的时候,开发人员可以使用工具生成分部方法,然后手动去实现方法。分部方法有以下几个限制,第一方法必须返回void,只能默认为private;第二,分部方法不能为virtual和extern方法;第三,分部方法可以有ref参数,但不能有out参数;

技术分享图片
1 partial void PersonChanged(Person person);
2
3 partial void PersonChanged(Person person)
4 {
5 PersonManager personManager=new PersonManager();
6 personManager.Update(person);
7 ......
8 }
技术分享图片

关于分部类与分部方法,在微软的官方网站上有着详细介绍,在这里不多作说明。而下面在下想介绍一下分部类与分部方法的实际用途,这才是我写这章文件的真的目的。

 

3).分部类与分部方法的可用性

LINQ是微软在Framewrok3.0开发推出的新产品,其中LINQ TO SQL是实现对象与数据表相映射的神奇工具。随着Framework 4.0面世,Entity Framework成为微软项目中实现ORM的主要手段,当中*.edmx文件中使用的都是分部类的实现方式。这是因为映射过程是自动生成的,代码必须符合定制的规则,当需要为对象添加一些额外的属性,而这些属性无需保存到数据库的时候,分部类就派上用场,我们可以使用分部类为对象提供各种的自定义属性。

特别是在使用DDD领域驱动设计的时候,分部类成为实现模型动作的一个好方法。失血模型与充血模型是DDD长久争议的话题,在失血模型中,模型是不应该具备动作,而是把动作放在Service层中,而在充血模型中,模型类应该具有各自的方法,而“分部类”就是实现充血模型方法的一种好手段。

技术分享图片
  1         //Model.Designer.cs文件  
2 [global::System.Data.Objects.DataClasses.EdmEntityTypeAttribute(
3 NamespaceName="BusinessModel", Name="Approve")]
4 [global::System.Runtime.Serialization.DataContractAttribute(IsReference=true)]
5 [global::System.Serializable()]
6 public partial class Approve : global::System.Data.Objects.DataClasses.EntityObject
7 {
8 /// <summary>
9 /// 创建新的 Approve 对象。
10 /// </summary>
11 /// <param name="id">ID 的初始值。</param>
12 /// <param name="functionType">FunctionType 的初始值。</param>
13 [global::System.CodeDom.Compiler.GeneratedCode("
14 System.Data.Entity.Design.EntityClassGenerator", "4.0.0.0")]
15 public static Approve CreateApprove(int id, int functionType)
16 {
17 Approve approve = new Approve();
18 approve.ID = id;
19 approve.FunctionType = functionType;
20 return approve;
21 }
22 /// <summary>
23 /// 架构中不存在属性 ID 的任何注释。
24 /// </summary>
25 [global::System.Data.Objects.DataClasses.EdmScalarPropertyAttribute(
26 EntityKeyProperty=true,IsNullable=false)]
27 [global::System.Runtime.Serialization.DataMemberAttribute()]
28 [global::System.CodeDom.Compiler.GeneratedCode(
29 "System.Data.Entity.Design.EntityClassGenerator", "4.0.0.0")]
30 public int ID
31 {
32 get
33 {
34 return this._ID;
35 }
36 set
37 {
38 this.OnIDChanging(value);
39 this.ReportPropertyChanging("ID");
40 this._ID = global::System.Data.Objects.DataClasses
41 .StructuralObject.SetValidValue(value);
42 this.ReportPropertyChanged("ID");
43 this.OnIDChanged();
44 }
45 }
46 [global::System.CodeDom.Compiler.GeneratedCode("
47 System.Data.Entity.Design.EntityClassGenerator", "4.0.0.0")]
48 private int _ID;
49 [global::System.CodeDom.Compiler.GeneratedCode("
50 System.Data.Entity.Design.EntityClassGenerator", "4.0.0.0")]
51 partial void OnIDChanging(int value);
52 [global::System.CodeDom.Compiler.GeneratedCode("
53 System.Data.Entity.Design.EntityClassGenerator", "4.0.0.0")]
54 partial void OnIDChanged();
55 /// <summary>
56 /// 架构中不存在属性 FunctionType 的任何注释。
57 /// </summary>
58 [global::System.Data.Objects.DataClasses
59 .EdmScalarPropertyAttribute(IsNullable=false)]
60 [global::System.Runtime.Serialization.DataMemberAttribute()]
61 [global::System.CodeDom.Compiler.GeneratedCode(
62 "System.Data.Entity.Design.EntityClassGenerator", "4.0.0.0")]
63 public int FunctionType
64 {
65 get
66 {
67 return this._FunctionType;
68 }
69 set
70 {
71 this.OnFunctionTypeChanging(value);
72 this.ReportPropertyChanging("FunctionType");
73 this._FunctionType = global::System.Data.Objects.DataClasses
74 .StructuralObject.SetValidValue(value);
75 this.ReportPropertyChanged("FunctionType");
76 this.OnFunctionTypeChanged();
77 }
78 }
79 [global::System.CodeDom.Compiler.GeneratedCode("
80 System.Data.Entity.Design.EntityClassGenerator", "4.0.0.0")]
81 private int _FunctionType;
82 [global::System.CodeDom.Compiler.GeneratedCode("
83 System.Data.Entity.Design.EntityClassGenerator", "4.0.0.0")]
84 partial void OnFunctionTypeChanging(int value);
85 [global::System.CodeDom.Compiler.GeneratedCode("
86 System.Data.Entity.Design.EntityClassGenerator", "4.0.0.0")]
87 partial void OnFunctionTypeChanged();
88 /// <summary>
89 /// 架构中不存在属性 Title 的任何注释。
90 /// </summary>
91 [global::System.Data.Objects.DataClasses.EdmScalarPropertyAttribute()]
92 [global::System.Runtime.Serialization.DataMemberAttribute()]
93 [global::System.CodeDom.Compiler.GeneratedCode("
94 System.Data.Entity.Design.EntityClassGenerator", "4.0.0.0")]
95 public string Title
96 {
97 get
98 {
99 return this._Title;
100 }
101 set
102 {
103 this.OnTitleChanging(value);
104 this.ReportPropertyChanging("Title");
105 this._Title = global::System.Data.Objects.DataClasses
106 .StructuralObject.SetValidValue(value, true);
107 this.ReportPropertyChanged("Title");
108 this.OnTitleChanged();
109 }
110 }
111 ...............................
112 }
113
114 //分部类
115 public partial class Approve
116 {
117 //添加属性
118 public string Type
119 {
120 get;set;
121 }
122
123 //添加动作
124 public void AddReport(Report report)
125 {.......}
126 .................
127 }

 

 

参考【C# 与 .net 4 高级程序设计(第五版)】整理总结

 











































































































































































以上是关于第四章:定义封装的类类型的主要内容,如果未能解决你的问题,请参考以下文章

VSCode自定义代码片段14——Vue的axios网络请求封装

VSCode自定义代码片段14——Vue的axios网络请求封装

VSCode自定义代码片段14——Vue的axios网络请求封装

《构建之法》阅读笔记三

JAVA学习日记6-0711

深入理解DOM节点类型第四篇——文档片段节点DocumentFragment