C#类

4933701-3af87747dc78c02a.png

结构与枚举

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();
        }    
    }
}

什么是类

  • 类是一种抽象的数据结构(data structure)
  • 类是一种数据类型
  • 类代表现实世界中的种类

类是一种活动的数据结构

类是一个能存储数据并执行代码的数据结构,包含数据成员和函数成员。数据成员,存储与类或类的实例相关的数据,数据成员通常模拟该类所表示的现实世界事物的特性。函数成员,执行代码,通常会模拟类所表示的现实世界事物的功能和操作。

类是一种数据结构,包含数据成员(常量和字段)、函数成员(方法、属性、事件、索引器、运算符、实例构造函数、静态构造函数、析构函数)、嵌套类型。类类型支持继承,继承是一种机制,使派生类可对基类进行扩展和专用化。

类是逻辑相关的数据和函数的封装,通常代表真实世界中或概念上的事物。

类成员

数据成员

  • 常量

常量与类相关,尽管没有static修饰符,编译器使用真实值代替常量。

常量与类的关联方式与变量与类的关联方式相同,使用const关键字来声明常量。如果将其声明为public则在类的外部可访问它。

class User
{
    //常量
    public const string Root = "Admin";
    //字段
    public int UserID;
    public string UserName;
}
  • 字段

字段是类的数据成员,是类型的一个变量,该类型是类的一个成员,也就是说字段是与类相关的变量。

  1. 字段可以是任何类型,无论是预定义类型还是用户自定义类型。
  2. 字段和变量一样,用来保存数据,并具有可被写入和可被读取的特征。
4933701-1d18fde8fb7e8632.png
字段

最好不要将字段声明为public,如果修改类的公共成员,使用公共成员的每个调用程序也需要更改。最好是将字段声明为private,使用属性来访问字段。

与C和C++不同的是,C#在类型的外部不能声明全局变量。所有的字段都属于类型,而且必须在类型声明内部声明。

字段初始化

因为字段是一种变量,所以字段初始化和变量初始化相同。

  1. 字段初始化语句是字段声明的一部分,由等号和求值表达式组成。
  2. 初始化值必须是编译时可确定的
  3. 若没有初始化语句,字段的值会被编译器设置为默认值,默认值由字段的类型决定。

函数成员

  • 属性

属性(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#为读写类中的属性提供了专用语法,所以不必使用名称中嵌入GetSet的方法。因为属性的这种语法不同于一般函数的语法。在客户端代码中,虚拟的对象被当作实际的东西。

get访问器不带任何参数且必须返回属性声明的类型,也不应该为set访问器指定任何显式参数,但编译器假定它带有一个参数,其类型也与属性相同,并表示为value

class User
{
    //属性
    private DateTime createTime;
    public DateTime CreatedTime
    {
        get
        {
            return createTime;
        }
        set
        {
            createTime = value;
        }
    }
}

命名约定

采用C#区分大小写模式,使用相同的名称,公有属性采用Pascal大小写形式命名。若存在一个等价的私有字段,则采用Camel大小写形式命名。在使用私有成员时,.NET Core团队使用下划线作为字段的前缀,.NET没有严格的命名约定。

自动实现的属性

若属性的setget访问器中没有任何逻辑,就可以使用自动实现的属性。该属性会自动实现后备成员变量。

public int UserID { get; set; }

此时无需声明私有字段,编译器会自动创建它。使用自动实现的属性,就不能直接访问字段,因为不知道编译器生成的名称。

使用自动实现的属性,就不能在属性设置中验证属性的有效性。

自动实现的属性可以使用属性初始化其来初始化

public DateTime CreateTime { get; set; } = DateTime.Now

属性的访问修饰符

C# 允许给属性的getset访问器设置不同的访问修饰符,属性可以有公有的get访问器和私有或受保护的set访问器。这有助于控制属性的设置方式或时间。

private string _username;
public string UserName
{
  // 公有的get访问器
  get
  {
    return _username;
  }
  // 私有或受保护的set访问器
  private set
  {
    _name = value;
  }
}

getset访问器中,必须有一个具备属性的访问级别。如果get访问器的访问级别是protected,会产生一个编译错误,因为会使两个访问器的访问级别都不是属性。

通过自动实现的属性,可以设置不同的访问级别。

public int UserID { get; private set; }
  • 方法
    方法是与特定类相关联的函数
  • 事件
    事件是类的成员,在发生某些行为时,如修改类的字段或属性,或进行某种形式的用户交互操作时,可以让对象通知调用方。客户可包含所谓“事件处理程序”的代码来响应事件。
  • 索引器
    索引器允许对象使用访问数组的方式访问
  • 运算符
    运算符执行的最简单的操作就是加法和减法,两个整数相加时,严格来说是对整数使用“+”运算符。C#允许指定把已有的运算符应用于自己的类(运算符重载)。
  • 构造函数
    构造函数是在实例化对象时自动调用的特殊函数,必须与所属类同名,且不能有返回值。构造函数用于初始化字段的值。
  • 析构函数
    析构函数或终结器的语法类似于构造函数的语法,在CLR检测到不再需要某个对象时调用,其名称与类相同,但前面有一个~符号。不可能预测什么时候调用终结器。

嵌套类型

类可以包含内部类,如果内部类只和外部类型结合使用则很有趣。

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修饰符。

类的声明与访问级别

  • 类声明的全貌 声明既定义(C#与Java)
  • 简单的类声明 类的访问控制
  • 类成员的访问控制
  • 类的继承
    • 派生类对基类的成员获得与访问
    • 在派生类中访问基类的成员
    • 构造器的不可继承性

类声明的位置

  • 声明在命名空间中
  • 声明在命名空间外,实际上在全局命名空间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++中类的声明和定义是分开的

4933701-2b2aca114e8eab73.png
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 <iostream>
#include "User.h"

int main()
{
    User *user = new User();
    user->Print();

    //std::cout << "Hello World!\n"; 
    return 0;
}

Java和C#中类的声明与定义放在一起

类声明

类的声明定义了新类的特征和成员,类声明并不创建类的实例,但创建了用于创建实例的模板。

类的声明提供以下内容:类的名称、类的成员、类的特征

4933701-a950c14f6beffc01.png
类的声明
4933701-4d0eb1bcb782b05c.png
类的声明

类修饰符

class-declaration 可以根据需要包含一个类修饰符序列,同一修饰符在一个类声明中多次出现是编译时错误。

4933701-eaa7304c8e161715.png
类修饰符

new修饰符适用于嵌套类,指定类隐藏同名的继承成员。如果在不是嵌套类声明的类声明中使用new修饰符,则会导致编译时错误。

访问修饰符(access modifier)

访问修饰符标识了所修饰成员的封装级别,可选择5个访问修饰符,即publicprotectedinternalprivateprotected 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;
    }
}

例如:仪表盘

仪表盘包含哪些部件和动作呢?
部件:表值、名称、零件
动作:指针转动、指针复位、显示度数

4933701-ca5f36ff460763a0.png
仪表盘

流程:

  1. class仅仅是定义,即自定义引用类型。使用class需要使用new进行实例化生成对象。
  2. 理解字段和访问修饰符,访问修饰符用于信息隐藏。
//获取表盘读数 
private double Value = 0;
public double GetValue()
{
    return this.Value;
}
public void SetValue(double value)
{
    this.Value = value;
}
  1. 理解方法和修饰符
  2. 理解关键字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);
}
  1. 理解属性
    灵活的属性,可提供验证,且保持只读只写。
//属性 惯用手法 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;
    }
}
  1. 构造器
    理解自定义构造器,例如实例化时必须定义Name,实例化时让指针清零。
    理解默认构造器,一旦有了自定义构造器,默认构造器则无效。
    理解构造器重载,定义多个构造器。
//构造器 无返回值
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}");
  1. 静态
    理解静态成员(全局性),属于类型而非实例。
  • 字段、属性:访问时无需实例化
//静态成员 属于类型 属性 共享
public static long Amount { get; set; }
  • 方法:内部不能使用this
//静态方法 静态只能调用静态
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;
}
  • 类:静态类如Math
//静态类
Console.WriteLine(Math.PI);
  1. 初探设计模式
    单例模式
//单例模式
private static DashBoard _Instance = null;
public static DashBoard Instance {
    get
    {
        if (_Instance == null)
        {
            _Instance = new DashBoard();
        }
        return _Instance;
    }  
}
  1. readonly
    readonly仅仅能在声明、构造函数中赋值。
    const在编译时固定,readonlly在运行时固定。
//readonly 声明时 运行时确定常量
readonly string guid = Guid.NewGuid().ToString();
  1. 嵌套类、分部类、分部方法(存在于分部类中的方法)

综合实例

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<Part> 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();
        }  
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值