using System;
namespace Test
{
//结构
struct User
{
public int age;
public string name;
public string firstname;
public string lastname;
}
//枚举 限定变量的可能性
enum Weekday
{
Monday=1,
Thuesday =2,
Wenesday=3,
Thursday=4,
Friday=5,
Saturday=6,
Sunday=7
}
class Program
{
static void Main(string[] args)
{
//使用结构体
User user = new User();
user.age = 20;
Console.WriteLine($"user age is {user.age}");//user age is 20
//使用枚举
Console.WriteLine(Weekday.Monday);//Monday
Console.WriteLine((int)Weekday.Monday);//1
Console.ReadKey();
}
}
}
类是一种活动的数据结构
类是一个能存储数据并执行代码的数据结构,包含数据成员和函数成员。数据成员,存储与类或类的实例相关的数据,数据成员通常模拟该类所表示的现实世界事物的特性。函数成员,执行代码,通常会模拟类所表示的现实世界事物的功能和操作。
类是一种数据结构,包含数据成员(常量和字段)、函数成员(方法、属性、事件、索引器、运算符、实例构造函数、静态构造函数、析构函数)、嵌套类型。类类型支持继承,继承是一种机制,使派生类可对基类进行扩展和专用化。
类是逻辑相关的数据和函数的封装,通常代表真实世界中或概念上的事物。
常量与类相关,尽管没有static
修饰符,编译器使用真实值代替常量。
常量与类的关联方式与变量与类的关联方式相同,使用const
关键字来声明常量。如果将其声明为public
则在类的外部可访问它。
class User
{
//常量
public const string Root = "Admin";
//字段
public int UserID;
public string UserName;
}
字段是类的数据成员,是类型的一个变量,该类型是类的一个成员,也就是说字段是与类相关的变量。
最好不要将字段声明为public
,如果修改类的公共成员,使用公共成员的每个调用程序也需要更改。最好是将字段声明为private
,使用属性来访问字段。
与C和C++不同的是,C#在类型的外部不能声明全局变量。所有的字段都属于类型,而且必须在类型声明内部声明。
字段初始化
因为字段是一种变量,所以字段初始化和变量初始化相同。
属性(property)是一个方法或一对方法,在客户端代码看来,它是一个字段。
class User
{
//常量
public const string Root = "Admin";
//字段
public int UserID;
public string UserName;
//属性
private string _password;
public string Password
{
get { return _password; }
set { _password = value; }
}
}
属性是可以从客户端访问的函数组,其访问方式与访问类的公共字段类似。C#为读写类中的属性提供了专用语法,所以不必使用名称中嵌入Get
或Set
的方法。因为属性的这种语法不同于一般函数的语法。在客户端代码中,虚拟的对象被当作实际的东西。
get
访问器不带任何参数且必须返回属性声明的类型,也不应该为set
访问器指定任何显式参数,但编译器假定它带有一个参数,其类型也与属性相同,并表示为value
。
class User
{
//属性
private DateTime createTime;
public DateTime CreatedTime
{
get
{
return createTime;
}
set
{
createTime = value;
}
}
}
命名约定
采用C#区分大小写模式,使用相同的名称,公有属性采用Pascal大小写形式命名。若存在一个等价的私有字段,则采用Camel大小写形式命名。在使用私有成员时,.NET Core团队使用下划线作为字段的前缀,.NET没有严格的命名约定。
自动实现的属性
若属性的set
和get
访问器中没有任何逻辑,就可以使用自动实现的属性。该属性会自动实现后备成员变量。
public int UserID { get; set; }
此时无需声明私有字段,编译器会自动创建它。使用自动实现的属性,就不能直接访问字段,因为不知道编译器生成的名称。
使用自动实现的属性,就不能在属性设置中验证属性的有效性。
自动实现的属性可以使用属性初始化其来初始化
public DateTime CreateTime { get; set; } = DateTime.Now
属性的访问修饰符
C# 允许给属性的get
和set
访问器设置不同的访问修饰符,属性可以有公有的get
访问器和私有或受保护的set
访问器。这有助于控制属性的设置方式或时间。
private string _username;
public string UserName
{
// 公有的get访问器
get
{
return _username;
}
// 私有或受保护的set访问器
private set
{
_name = value;
}
}
在get
和set
访问器中,必须有一个具备属性的访问级别。如果get
访问器的访问级别是protected
,会产生一个编译错误,因为会使两个访问器的访问级别都不是属性。
通过自动实现的属性,可以设置不同的访问级别。
public int UserID { get; private set; }
~
符号。不可能预测什么时候调用终结器。类可以包含内部类,如果内部类只和外部类型结合使用则很有趣。
using System;
namespace Test
{
class User
{
public int ID { get; set; }
public string UserName { get; set; }
public void Report()
{
Console.WriteLine($"I am user #{ID}, my name is {UserName}.");
}
//实例构造器
public User(int id, string username)
{
this.ID = id;
this.UserName = username;
Amount++;
}
//实例析构器 托管语言
~User()
{
Amount--;
Console.WriteLine("Release the system resource...");
}
//静态成员
public static int Amount { get; set; }
//静态构造器 只能构造静态成员
static User()
{
Amount = 100;
}
}
class Program
{
static void Main(string[] args)
{
//声明类并创建类的实例,使用默认构造器
//User user = new User() {
// ID = 1,
// UserName = "JunChow"
//};
//user.Report();
//使用实例构造器实例化对象
//User user = new User(100, "junchow");
//user.Report();
//使用反射创建类
//Type t = typeof(User);
//object obj = Activator.CreateInstance(t, 200, "alice");//创建实例
//Console.WriteLine(obj.GetType().Name);//User
//Console.WriteLine(obj is User);//True
//User user = obj as User;
//user.Report();
//动态类型
//Type t = typeof(User);
//dynamic u = Activator.CreateInstance(t, 300, "alibaba");
//u.Report();
//调用静态
Console.WriteLine(User.Amount);
User u1 = new User(1000, "Jacky");
User u2 = new User(2000, "Tim");
Console.WriteLine(User.Amount);
Console.ReadKey();
}
}
}
类包含成员,成员可以是静态或实例。静态成员属于类,实例成员属于对象。静态字段的值对每个对象都是相同的。而每个对象的实例字段都可以有不同的值。静态成员关联了static
修饰符。
类声明的位置
Global
下。using System;
namespace Test
{
/*在命名空间中声明类*/
class User
{
}
class Program
{
static void Main(string[] args)
{
Console.ReadKey();
}
/*成员类:在类中声明类*/
class Inner
{
}
}
}
namespace NS
{
class Member
{
}
}
/*在类声明在所有命名空间在外,实际上它声明在全局名称空间Global下。*/
class Klass
{
}
声明declare
与定义define
C++中类的声明和定义是分开的
$ vim User.h
class User
{
public:
User();
~User();
void Print();
};
$ vim User.cpp
#include "pch.h"
#include "User.h"
#include "iostream"
User::User()
{
}
User::~User()
{
}
void User::Print() {
std::cout << "Hello" << std::endl;
}
$ vim ConsoleApp.cpp
#include "pch.h"
#include
#include "User.h"
int main()
{
User *user = new User();
user->Print();
//std::cout << "Hello World!\n";
return 0;
}
Java和C#中类的声明与定义放在一起
类的声明定义了新类的特征和成员,类声明并不创建类的实例,但创建了用于创建实例的模板。
类的声明提供以下内容:类的名称、类的成员、类的特征
类修饰符
class-declaration 可以根据需要包含一个类修饰符序列,同一修饰符在一个类声明中多次出现是编译时错误。
new
修饰符适用于嵌套类,指定类隐藏同名的继承成员。如果在不是嵌套类声明的类声明中使用new
修饰符,则会导致编译时错误。
访问修饰符(access modifier)
访问修饰符标识了所修饰成员的封装级别,可选择5个访问修饰符,即public
、protected
、internal
、private
、protected internal
修饰符将控制类的可访问性,根据类声明所处的上下文,可访问性修饰符可能不允许使用。
封装:信息隐藏
除了组合数据和方法,封装的另一个重要作用是隐藏对象的数据和行为的内部细节。方法在某种程序上也能做到这一点,在方法外部,调用者看到的只是方法声明,内部实现不可见。面向对象编程更进一步,它能控制类成员在类外部的可视程度。在类的外部不可见的成员称为私有成员。
在面向对象编程中,封装的作用不仅仅是组合数据和行为,还能隐藏类中的数据和行为的实现细节,使类的内部工作机制不被暴露。这减少了调用者对数据进行不恰当修改的几率。
访问修饰符的作用是提供封装,如果不为类成员添加访问修饰符则默认使用private
,即成员默认为私有成员。公共成员必须显式指定。
class Employee
{
public string FirstName;
public string LastName;
public double Salary;
//允许调用Employee对象并用Logon()方法验证密码,但不允许从类的外部访问Employee对象的Password字段。
//为了隐藏Password字段,禁止从它的包容类的外部访问,应使用private访问修饰符替代public。
private string Password;
private bool IsAuthenticated;
public bool Logon(string password)
{
if(Password == password)
{
IsAuthenticated = true;
}
return IsAuthenticated;
}
public bool GetIsAuthenticated()
{
return IsAuthenticated;
}
}
例如:仪表盘
仪表盘包含哪些部件和动作呢?
部件:表值、名称、零件
动作:指针转动、指针复位、显示度数
流程:
class
仅仅是定义,即自定义引用类型。使用class
需要使用new
进行实例化生成对象。//获取表盘读数
private double Value = 0;
public double GetValue()
{
return this.Value;
}
public void SetValue(double value)
{
this.Value = value;
}
this
,例如将读数保存到数据库。//数据库操作类
class DB
{
public bool Store(DashBoard dashboard)
{
double val = dashboard.GetValue();
//...
return true;
}
}
//保存读数到数据库
public bool Save()
{
DB db = new DB();
return db.Store(this);
}
//属性 惯用手法 getter和setter
//获取表盘读数
public double GetValue()
{
return this.Value;
}
public void SetValue(double value)
{
this.Value = value;
}
//属性
public string Name
{
get { return _Name; }
//value为上下文关键字,仅仅在特定环境下才有确切含义。
set { _Name = value; }
}
//属性自动实现
public string Name {
//只读
get
{
return _Name;
}
//只写 private 仅仅内部可写
set
{
if (string.IsNullOrEmpty(value))
{
throw new ArgumentException();//抛出参数异常
}
_Name = value;
}
}
//构造器 无返回值
public DashBoard()
{
Amount++;//静态属性
this.Reset();
}
public DashBoard(string name):this() //此处this()调用默认构造器
{
if (string.IsNullOrEmpty(name))
{
this.Name = "unknow";
}
else
{
this.Name = name;
}
}
理解this调用构造器
//构造器 无返回值
public DashBoard()
{
Amount++;//静态属性
this.Reset();
}
public DashBoard(string name):this() //此处this()调用默认构造器
{
if (string.IsNullOrEmpty(name))
{
this.Name = "unknow";
}
else
{
this.Name = name;
}
}
理解对象初始化器,扩展集合初始化器、终结器、匿名对象。
//对象初始化器
DashBoard dashboard1 = new DashBoard()
{
Name = "油表盘"
};
dashboard1.Show();
//匿名对象
var user = new { UserID = 1, UserName = "JunChow" };
Console.WriteLine($"user#{user.UserID}: {user.UserName}");
//静态成员 属于类型 属性 共享
public static long Amount { get; set; }
//静态方法 静态只能调用静态
public static void ResetAmount()
{
Amount = 0;
}
//静态成员 属于类型 属性 共享
public static long Amount { get; set; }
//静态构造函数 无public修饰符
//public static是不完整的修饰符,后面要加上 void,String,int等类型,表示方法是静态方法。
static DashBoard()
{
Amount = 0;
}
//静态方法 静态只能调用静态
public static void ResetAmount()
{
Amount = 0;
}
//静态类
Console.WriteLine(Math.PI);
//单例模式
private static DashBoard _Instance = null;
public static DashBoard Instance {
get
{
if (_Instance == null)
{
_Instance = new DashBoard();
}
return _Instance;
}
}
readonly
仅仅能在声明、构造函数中赋值。const
在编译时固定,readonlly
在运行时固定。//readonly 声明时 运行时确定常量
readonly string guid = Guid.NewGuid().ToString();
综合实例
using ClassLibrary.NS;
using System;
using System.Collections.Generic;
namespace Test
{
//数据库操作类
class DB
{
public bool Store(DashBoard dashboard)
{
double val = dashboard.GetValue();
//...
return true;
}
}
//定义类 零件
class Part
{
}
//定义类 仪表盘
class DashBoard
{
//字段
private string _Name = "unknow";
private double Value = 0;
public List Parts = null;
//静态成员 属于类型 属性 共享
public static long Amount { get; set; }
//属性 惯用手法 getter和setter
//获取表盘读数
public double GetValue()
{
return this.Value;
}
public void SetValue(double value)
{
this.Value = value;
}
//属性
//public string Name {
// get { return _Name; }
// //value为上下文关键字,仅仅在特定环境下才有确切含义。
// set { _Name = value; }
//}
//属性自动实现
public string Name {
//只读
get
{
return _Name;
}
//只写 private 仅仅内部可写
set
{
if (string.IsNullOrEmpty(value))
{
throw new ArgumentException();//抛出参数异常
}
_Name = value;
}
}
//指针复位
private void Reset()
{
Value = 0.0;
}
//表盘转动
public void Rotate(double degree)
{
Value = degree;
}
//显示读数
public void Show()
{
Console.WriteLine("{0}: {1}", Name, Value);
}
//保存读数到数据库
public bool Save()
{
DB db = new DB();
return db.Store(this);
}
//构造器 无返回值
public DashBoard()
{
Amount++;//静态属性
this.Reset();
}
public DashBoard(string name):this() //此处this()调用默认构造器
{
if (string.IsNullOrEmpty(name))
{
this.Name = "unknow";
}
else
{
this.Name = name;
}
}
//静态构造函数 无public修饰符
//public static是不完整的修饰符,后面要加上 void,String,int等类型,表示方法是静态方法。
static DashBoard()
{
Amount = 0;
}
//静态方法 静态只能调用静态
public static void ResetAmount()
{
Amount = 0;
}
//单例模式
private static DashBoard _Instance = null;
public static DashBoard Instance {
get
{
if (_Instance == null)
{
_Instance = new DashBoard();
}
return _Instance;
}
}
//readonly 声明时 运行时确定常量
readonly string guid = Guid.NewGuid().ToString();
}
class Program
{
static void Main(string[] args)
{
//实例化
DashBoard dashboard = new DashBoard("仪表盘");
//dashboard.Name = "仪表盘";
//dashboard.Reset();
dashboard.Rotate(10.0);
dashboard.Show();
dashboard.Save();
//对象初始化器
DashBoard dashboard1 = new DashBoard()
{
Name = "油表盘"
};
dashboard1.Show();
//集合对象初始化器
//匿名对象
var user = new { UserID = 1, UserName = "JunChow" };
Console.WriteLine($"user#{user.UserID}: {user.UserName}");
//终结器
//静态属性
Console.WriteLine(DashBoard.Amount);
DashBoard.ResetAmount();
Console.WriteLine(DashBoard.Amount);
//静态类
Console.WriteLine(Math.PI);
//单例模式
var instance1 = DashBoard.Instance;
instance1.Name = "jacky";
instance1.Show();
var instance2 = DashBoard.Instance;
instance2.Name = "junchow";
instance2.Show();
var instance3 = DashBoard.Instance;
instance3.Show();
Console.ReadKey();
}
}
}