在前面的学习中,我间接提到了一些关于方法,类和面向的对象的一些概念,但是所描述的概念并不是很专业,并且很肤浅。也是鉴于本人水平并不高,如果哪里有错误,也请大家具体指出。
起初我刚接触到面向对象这个概念时候,感觉和PLC中写的FB块很像,就是将一些数据,和一下业务逻辑封装到一起,组成一个方法
方便我们重复的使用。稍微有点不同的是,C#中的方法依存于类中,我们要在类中创建方法才有意义。
我们把这些具有相同属性和相同方法的对象进行进一步的封装,抽象出类的概念。类就是个模子,确定了对象应该具有的属性和方法。对象是根据类创建出来的。
所有面向对象的编程语言,都是我们吧要处理的“数据”和“行为”(方法)封装到类中。
类的语法
[public] class 类名
{
字段;
属性;
方法;
}
写好一个类后,我们需要创建这个类的对象,这个过程为类的实例化。this关键字表示当前类的对象。
创建流程如下:
1.设计类:就是根据需求设计各种类,为每一个类设计对应的“数据存储”和“操作内容”
2.关联类:我们所设计的对象,他们之间是有一定关联的,正是按照这种关系,完成对象的交互。
3.使用类:根据我们的需要,使用我们所设计的类,使用的时候通过对象的方式调用。
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace 草稿 8 { 9 public class Person 10 { 11 public string _name; 12 public int _age; 13 public char _gender; 14 15 public void CHLSS() 16 { 17 Console.WriteLine("我叫{0},我今年{1}岁了,我是{2}生,我可以吃喝拉撒睡~~~",this._name,this._age,this._gender); 18 } 19 } 20 }
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace 草稿 8 { 9 class Program 10 { 11 static void Main(string[] args) 12 { 13 //创建对象 14 Person LXB = new Person(); 15 LXB._name = "LXB"; 16 LXB._age = -23; 17 LXB._gender = ‘男‘; 18 LXB.CHLSS(); 19 Console.ReadKey(); 20 } 21 } 22 }
类是不占内存的,对象是占内存的。我们在仔细观察上面程序,在实际变成当中,年龄是不许有负数的,是非法的。这时,我们需要引入属性这个概念,他的作用就是保护字段,对字段的赋值和取值进行限定。创建对象要在方法中。
属性的语法;
public string Name
{
get{return _name;}
set{_name=value;}
}
属性的使用:
作用:在OOP中主要用来封装数据。
要求:一般采用Pascal命名法,数据类型和字段要一致,使用public修饰。
其实C#发展至今,属性的语法写法如下:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace 草稿 8 { 9 public class Ticket 10 { 11 //C#2.0时代标准属性 12 private double _distance; 13 14 public double Distance 15 { 16 get { return _distance; } 17 set { _distance = value; } 18 } 19 20 //C#3.0时代,对标准属性做了简化(以后,标准属性,都可以这样用) 21 public int Price { get; set; } 22 23 //C#4.0时代,增加属性表达式(下面写法不常用) 24 private double unitPrice=4000; 25 public double UnitPrice { get => unitPrice; set => unitPrice = value; } 26 27 //C#4.0时代以后,可以直接赋值。 28 public string Type { get; set; } = ".Net开发系列"; 29 30 } 31 }
在这几种方法中,没有显示写出对应的私有字段,编译器都会帮我们自动生成。可以通过reflector查看。
属性的本质就是两个方法,一个叫get(取值)一个叫set(赋值)。在我们实际应用中,不是所有属性都有get和set方法,要过呢据实际情况而定。外界不能随便访问到我们的字段,所以更改如下
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace 草稿 8 { 9 public class Person 10 { 11 private string _name; 12 public string Name 13 { 14 get { return _name; } 15 set { _name = value; } 16 } 17 18 private int _age; 19 public int Age 20 { 21 get { return _age; } 22 set 23 { 24 if (value<0||value>100) 25 { 26 value = 0; 27 } 28 _age = value; 29 } 30 } 31 32 private char _gender; 33 public char Gender 34 { 35 get { return _gender; } 36 set { _gender = value; } 37 } 38 39 public void CHLSS() 40 { 41 Console.WriteLine("我叫{0},我今年{1}岁了,我是{2}生,我可以吃喝拉撒睡~~~",this.Name,this.Age,this.Gender); 42 } 43 } 44 }
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace 草稿 8 { 9 class Program 10 { 11 static void Main(string[] args) 12 { 13 //创建对象 14 Person LXB = new Person(); 15 LXB.Name = "LXB"; 16 LXB.Age = 23; 17 LXB.Gender = ‘男‘; 18 LXB.CHLSS(); 19 Console.ReadKey(); 20 } 21 } 22 }
当我们创建好一个类的对象后,要给这个对象的每个属性去赋值,这个过程叫对象的初始化。
读取:属性通过get方法,返回私有字段。
赋值:属性通过set方法,借助value给私有字段赋值。
本质:属性本身其实并没有保存数据,而字段才是真正数据的存储单元。在属性get和set方法中添加业务逻辑。
总结:属性和字段
字段(成员变量)
(1)内部使用:字段主要是为类的内部数据交互使用,字段一般为private.
(2)数据存储:字段只是用来存储数据,如果不是静态数据,生命周期和对象共存亡。
(3)读写不限:我们可以给字段赋值,也可以获取字段的值(readonly除外)。
属性(字段封装)
(1)外部使用:属性一般是向外提供数据访问,属性是public修饰,用来对外表示对象的静态特征。
(2)业务扩展:属性内部可以添加我们需要的业务逻辑,可以避免非法数据,或完成其他相关任务。
(3)读写可控:属性可以根据需要设置为只读属性,更好地体现面向对象的“封装特性”!也就是安全性!
使用
(1)常规化使用:对象本身的“对外”数据保存,都是通过属性完成的,调用者都可以使用
(2)强制性使用:公有化字段,在很多时候是无法被解析的。(比如dgv,combobox的显示问题)。
静态方法和非静态方法区别
(1)在非静态类中,既可以有实例成员,也可以有静态成员。
(2)在调用实例成员的时候,需要使用对象名.实例成员。
在调用静态成员的时候,需要使用类名.静态成员名。
总结:静态成员必须使用类名去调用,而实例成员使用对象名。静态函数中,只能访问静态成员,不允许访问实例成员。
1)如果想要将你的类当作一个“工具类”,可以考虑将类写成静态类。
2)静态类在整个项目中资源共享。(静态存储区)只有在程序全部结束轴,静态类才会释放资源。
在给对象初始化的时候,我们可以用构造函数。
构造函数是一个特殊的方法
(1)构造函数没有返回值,连void都不能有。
(2)创建对象的时候会执行构造函数。
(3)类当中会有一个默认的无参的构造函数,当你写一个新的构造函数之后,不管有参无参,那个无参的构造函数都会被干掉。
this关键字的作用:
1.代表当前类的对象。
2.在类当中显示嗲用本类的构造函数。:this
析构函数的概念:
当程序结束的时候,析构函数才能执行。帮助我们释放资源。
下面我们做一个练习:写一个Ticket类,有一个距离属性(只读),在构造方法中赋值。不能为负数,有一个价格属性,并根据距离distance计价Price(1元/公里)
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace 草稿 8 { 9 public class Ticket 10 { 11 private double _distance; 12 13 public double Distance 14 { 15 get { return _distance; } 16 } 17 18 private double _price; 19 20 public double Price 21 { 22 get 23 { 24 if (_distance>0 && _distance<= 100) 25 { 26 return _distance * 1.0; 27 } 28 else if (_distance>=101 && _distance<200) 29 { 30 return _distance * 0.95; 31 } 32 else if (_distance>=201 && _distance<300) 33 { 34 return _distance * 0.9; 35 } 36 else 37 { 38 return _distance * 0.8; 39 } 40 } 41 } 42 43 public Ticket(double distance) 44 { 45 if (distance<0) 46 { 47 distance = 0; 48 } 49 this._distance = distance; 50 } 51 52 public void ShowTicket() 53 { 54 Console.WriteLine("{0}公里需要{1}元",Distance,Price); 55 } 56 57 58 } 59 }
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace 草稿 8 { 9 class Program 10 { 11 static void Main(string[] args) 12 { 13 Ticket t = new Ticket(90); 14 t.ShowTicket(); 15 Console.ReadKey(); 16 } 17 } 18 }
C#构造方法的补充
构造方法的作用:
因为构造方法是在对象创建的时候被调用的,所以,我们在创建的时候,可以完成一些初始化的任务。
初始化:包括给对象的属性赋值,或从其他对象,文本等获取基础数据。
构造方法的类型:
(1)无参数的构造方法:一个类中,如果没有显示的写出构造方法,编译器会默认生成一个无参的构造方法。我们也可以 随时显示添加一个无参数的构造 方法。通常是用来直接初始化对象的属性或“某些不变的数据”。
(2)有参数的构造方法:让对象创建者,自己传递要初始化的相关数据。
对象初始化器的使用
引入:C#3.0时代开始
作用:更加灵活的初始化对象的“属性”
语法:
对象类型 对象名=new 对象类型()
{
成员名1=value1,
成员名2=value2,
}
构造方法
1)存在的必要性:一个类中,至少要有一个构造方法。(可以无参数,也可以有参数的)
2)调用的特殊性:只能在对象创建的时候,通过new关键字调用。
3)使用的强制性:对象的创建,必须调用指定的构造方法,也就是参数必须统一。
4)语法的特殊性:不能有返回值,构造方法必须和类名一样。
构造方法PK对象初始化器
相同点:都可以完成对象“属性”初始化
不同点:1.有无强制性:构造方法有强制性,对象初始化器没有强制性,随意使用。
2.使用的范围:对象初始化器只能完成属性初始化,而构造方法可以完成任何需要的初始化任务。
3.使用的位置:对象初始化器在创建对象的时候使用,而构造方法必须提前写在类中。
4.出现的时间:构造方法在.Net1.0版本就有,而对象初始化器只能在.Net3.0以上版本才能使用。
注意:成员变量和局部变量同名时,一般实就近原则取变量,如果我们舍近求远,则必须添加this。
对象的生存周期
对象在内存中不断的“生生死死”,具有生命周期。
对象在内存中的状态
正在引用:程序正在使用对象。
游离状态:没有引用对象,已经使用完毕但依然占用空间。
我们可以显示的清除对象的引用,也就是仅为一个变量名,没有具体对象指向。对象名称=null
托管运行环境下对象的销毁由虚拟机负责,析构函数没多大用途。