博文适用于编程小白,基于《叩响C#之门》,传送门:链接:https://pan.baidu.com/s/1y2UegjDUJz-xrOQu3qKMjQ 密码:4v2n
《叩响C#之门》通俗易懂,又不失专业性,比传统的《C#入门经典》《C#从入门到精通》这类书好的多,是一本不可多得的好教材。
C#学习笔记(一)——第一章:初识编程
C#学习笔记(二)——第二章:变量
C#学习笔记(三)——一、二章内容练习及一些杂项
C#学习笔记(四)——第三章:运算符和表达式
C#学习笔记(五)——第四章:流程控制
C#学习笔记(六)——第五章:枚举、结构体和数组(还没写好)
C#学习笔记(七)——第六章:函数
C#学习笔记(八)——第七章:面向对象编程(一)
例子:
创建这么一个类——猫类。
它有3个属性
①名字
②年龄
③抓到的老鼠数(私有)
它有3个方法
①喵喵叫
②捉老鼠
③打招呼(私有)
类代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HelloClass2
{
class Cat
{
//字段成员
public string name;
public int age;
private int miceCount = 0; //用于记录捉到了多少只老鼠
//方法成员
//方法:打招呼
private void Hello()
{
Console.Write("Hi,我是{0}", name);
}
//方法:喵喵叫
public void Meow()
{
Hello();
Console.WriteLine("喵,喵~~~~");
}
//方法:捉老鼠
public void ChaseMice()
{
miceCount++;
Hello();
Console.WriteLine("我已经抓住了{0}只老鼠!", miceCount);
}
}
}
主函数
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HelloClass2
{
class Program
{
static void Main(string[] args)
{
//声明对象
Cat kitty = new Cat();
//访问数据成员
kitty.name = "Kitty";
kitty.age = 3;
Console.WriteLine("hi,我是{0},我{1}岁了。", kitty.name, kitty.age);
//调用方法
kitty.Meow();
kitty.ChaseMice(); //捉老鼠(私有属性micecount在这里体现)
kitty.ChaseMice(); //再次捉老鼠
}
}
}
动图
说白了就是两种构造实例的方式。第一种略显迂腐,第二种简洁且代码清晰。且python中更倾向于第二种。
说到面向对象编程(OOP)的属性,就有的聊了。
先说个题外话,有没有想过,为什么很多(甚至全部)OOP中,类的定义,实例,都会有且只有2种大的分类——①属性②方法?为什么没有第③种XX?为什么这两种刚好就是这2个?有没有觉得突兀?是谁规定的?
这个问题的回答,颇有些哲学的意味,但是这却是客观世界的真理!
我们都知道,OOP是一种贴近客观世界的描述物体的编程思想。那么想一下,给你个篮球,让你尽可能的描述它,你会怎么说?
嗯,,,能弹起来,大概100块,橘黄色,表面摩擦系数0.4,能充气,直径30cm,有点软,能滚动,1斤重……差不多就这些了。
自己想一下这些描述的词语,我们发现他们能且刚好能被归为2大类
1.大概100块,橘黄色,表面摩擦系数0.4,直径30cm,有点软,1斤重
2.能弹起来,能充气,能滚动,
这第1类,是用来描述物体性质的,被称为属性。
第2类,是用来描述物体能干什么的,被称为方法。
其实,不止是篮球,世间万物都可以用这两大类——属性,方法来完整刻绘。
所以,在OOP中,类的定义也好,实例自身也好,都有且刚好只有这两大类数据——属性,方法。
言归正传。
属性这个东西,有个非常非常典型,非常非常常用的操作,甚至可以说是每种编程语言都会用到的操作——设置,读取。
这个从客观事物的角度很好理解,属性嘛,物体自身的性质,自然会用到读取,和设置两种操作(如果你说有的属性我不用啊,那就不用设置,读取了。对,那你想想,如果你不用这种属性,干嘛写在类里(微笑脸)。)。
那么问题来了,我们最直接的设置方法,就是直接用点运算符进行赋值。但是这也会带来一个问题——设置的值没有经过任何检查,可能会使值不合理,比如学生的成绩student1.score=-19
。这就会出现意想不到的错误。该怎么办呢?再进一步想,我们可以给输入的数值进行一定的操作,来进行检查。进行操作,就需要用到函数(类中的方法)。比如这样
但是问题又来了!属性,最直接的访问方法一定是用点运算符,而非用函数。你想想,student.score=77
看着舒服,还是student.SetScore(77)
舒服?这便捷性和功能性似乎有矛盾——方便快捷的,功能性不强;功能强的,又不方便。有没有两全其美的办法呢?——又便捷,功能又强大。答案是——有!
基于这种对物体性质这种经常性的操作,很多编程语言都专门设置了一种方法,用来实现我们想要的又快捷又功能强的操作。比如python中的@setter
,@getter
装饰器。C#当然也有。请看下面例子
空
构造函数,顾名思义,就是用来按照图纸(类定义)生产产品(实例)的函数。
每个实例的生成,都必须要用到构造函数。就如Cat kitty=new Cat();
,这里的Cat()
就是默认的构造函数。构造函数在创建实例时,会给成员变量分配初始化的值。默认函数通常给的值都是null
,0
这些。
有时候我们需要设定初始值,该怎么办呢?用自定义的构造函数!
C#里面的构造函数相当于python类中的
__init__
。道理差不多的。
例子:(还是用最初的类代码)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HelloClass2
{
class Cat
{
//字段成员
public string name;
public int age;
private int miceCount = 0; //用于记录捉到了多少只老鼠
//方法成员
//方法:打招呼
private void Hello()
{
Console.Write("Hi,我是{0}", name);
}
//方法:喵喵叫
public void Meow()
{
Hello();
Console.WriteLine("喵,喵~~~~");
}
//方法:捉老鼠
public void ChaseMice()
{
miceCount++;
Hello();
Console.WriteLine("我已经抓住了{0}只老鼠!", miceCount);
}
}
}
主程序代码
//声明对象
Cat kitty = new Cat();
Console.WriteLine("姓名:{0}", kitty.name);
Console.WriteLine("年龄:{0}", kitty.age);
kitty.ChaseMice();
自定义构造函数位置:类内
自定义构造函数格式:public Cat(string nameValue,int ageValue)
(参数可选)
在类内添加代码
public Cat(string nameValue, int ageValue)
{
name = "kitty2"; //可以直接在这里赋给默认值
age = ageValue;
Console.WriteLine("一只猫诞生了!调用了构造函数!");
}
既然参数是可选的,我们来试一试
类代码:
public Cat()
{
name = "kitty2"; //可以直接在这里赋给默认值
age = 3;
Console.WriteLine("一只猫诞生了!调用了构造函数!");
}
效果
2句话总结:①在C#中可以不用管析构的问题,因为C#中有垃圾回收器。②真要写析构函数,可以按如下格式来写
~Cat() //函数名与类名相同,前面加~,函数体没有内容
{
}
实例:
在Cat()类中添加
~Cat()
{
Console.WriteLine("这只猫去了天堂~~~");
}
主程序
//声明对象
Cat kitty = new Cat();
kitty.Meow();
kitty.ChaseMice();
kitty.ChaseMice();
Console.WriteLine("\n其它语句:");
Console.WriteLine("------------");
Console.WriteLine("-------------");
Console.WriteLine("这是最后一条语句。");
效果:
类代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp9
{
class Time
{
/*-----------以下为私有成员--------------*/
private int hour;
private int minunt;
private int second;
private void SetTime(int h, int m, int s)
{
Hour = h;
Minunt = m;
Second = s;
}
/*-----------以下为公有成员--------------*/
//属性:Hour
public int Hour
{
get
{
return hour;
}
set
{
hour = ((value >= 0 && value < 24) ? value : 0);
}
}
//属性:Minunt
public int Minunt
{
get
{
return minunt;
}
set
{
minunt = ((value >= 0 && value < 60) ? value : 0);
}
}
//属性:Second
public int Second
{
get
{
return second;
}
set
{
second = ((value >= 0) && (value < 60) ? value : 0);
}
}
//构造函数:无参数
public Time()
{
SetTime(0, 0, 0);
}
//构造函数:一个参数
public Time(int hourValue)
{
SetTime(hourValue, 0, 0);
}
//构造函数:三个参数
public Time(int hourValue, int minuntValue, int secondValue)
{
SetTime(hourValue, minuntValue, secondValue);
}
//方法:返回24小时时间制
public string ToString24()
{
string output = Hour + ":" + Minunt + ":" + Second;
return output;
}
//方法:返回12小时制
public string ToString12()
{
int hour12 = (Hour == 12) || (Hour == 0) ? 12 : (Hour % 12);
string AMPM = (Hour < 12) ? "AM" : "PM";
string output = hour12 + ":" + Minunt + ":" + Second + AMPM;
return output;
}
}
}
主程序代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp11
{
class Program
{
static void Main(string[] args)
{
Time time1 = new Time();
Time time2 = new Time(22);
Time time3 = new Time(22, 36, 30);
string a = time1.ToString24();
Console.WriteLine("time1:");
Console.WriteLine("24小时制时间:"+ a);
Console.WriteLine("12小时制时间:"+ time1.ToString12()+"\n");
Console.WriteLine("time2:");
Console.WriteLine("24小时制时间:" + time2.ToString24());
Console.WriteLine("12小时制时间:" + time2.ToString12()+"\n");
Console.WriteLine("time3:");
Console.WriteLine("24小时制时间:" + time3.ToString24());
Console.WriteLine("12小时制时间:" + time3.ToString12()+"\n");
}
}
}