Keep on going never give up.

Let's Go

C# 学习笔记(21)类

C#Lonely2019-05-07 07:00:0035次0条

C#是一种面向对象的语言,面向对象语言的一个基本特征就是它们都有类,类是面向对象程序设计中的概念,是面向对象编程的基础

类的实质是一种数据类型,类似于int、char等基本类型,不同的是类是一种复杂的数据类型。因为它的本质是类型,而不是数据,所以不存在于内存中,不能被直接操作,只有被实例化为对象时,才会变得可操作。

类是对现实生活中一类具有共同特征的事物的抽象。在现实生活中,人就是一个类,但人只是一个抽象的概念,它指的是所有人。如果我们想找人聊天,此时就需要某个具体的人,比如我就是“人”类的一个实例。人这个类别中的个体,都有一些共同的特性(例如:姓名、性别、年龄等)和行为(例如:吃饭、工作、睡觉、思考等),所以在C#中,类代表一组具有公共属性和行为的对象

在C#中定义一个类的基本格式如下:

[访问修饰符] class 类名称

{

//类成员的定义

}

默认情况下,如果class关键字前没有显式地指定访问修饰符,则类的访问修饰符为internal,表示仅在当前项目内可被访问。当然也可显式地使用internal修饰符来定义类,但完全没有必要,因为默认修饰符就是internal。

C#中的五种访问修饰符传送门,可以修饰类的修饰符如下表格所示。

修饰符 访问权限
无或internal 只能在同一个程序(项目)集中访问(internal是类的默认访问修饰符)
public 公开的,同一程序集或引用该程序集的其他程序集都可以访问
abstract或internal abstract 只能在同一程序集中访问类,该类不能被实例化,只能被继承
public abstract 同一程序集或引用该程序集的其他程序集都可以访问类,不能被实例化,只能被继承
sealed或internal sealed 只能在同一程序集中访问类,该类不能被继承,只能被实例化
public sealed 同一程序集或引用该程序集的其他程序集都可以访问类,不能被继承,只能被实例化

可访问性不一致的问题:子类的访问权限不能高于父类的访问权限,因为这样会暴露父类个成员。


类的成员

定义完类之后,还需要在类中定义成员。类的成员包括字段、属性、方法、和构造函数等,它们与类一样,也都有自己的访问权限。

格式: [成员修饰符] 类的成员字段或者成员函数等;

例字段:protected 数据类型 字段名; //受保护的,只能在当前类的内部以及该类的子(派生)类中访问。类中的成员默认的访问修饰符是protected。

若使用static关键字将其声明为类的静态成员,则其不属于类的实例(类的实例也叫作类的对象),因为静态成员属于类级别的概念。

使用不同的修饰符将直接导致类的成员具有不同的访问权限。


属性

属性是对字段的扩展,根据面向对象语言的封装思想,字段的访问修饰符最好设为private,因为这样可以防止客户端直接对字段进行纂改,从而保证了内部成员的完整性。于是为了访问类中的私有字段,C#提供了属性这种机制,用来对字段进行灵活的控制和访问。

属性的作用就是保护字段,可以对字段的赋值和取值进行限定。属性定义主要由get访问器和set访问器组成,get访问器负责对字段进行读取,set访问器负责为字段进行赋值(它通过value隐式参数来表示用户传入的值),属性的本质就是两个方法,get方法用来返回字段,set方法用来把用户传入的值赋值给字段。

普通属性定义的格式:

public 数据类型 属性名

{

get { return 字段名; } //get访问器,当你输出属性的值的时候,会执行get方法

set { 字段名 = value; } //set 访问器,当你给属性赋值的时候,首先会执行set方法

}

快速生成普通属性的方法:键入“propfull”连按两次“Tab”,自动生成后再修改数据类型、属性名和变量名。

注:属性的数据类型必须与访问字段的数据类型一致。

代码示例:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp
{
    class Person
    {
        private string name; //私有字段定义
        
        //公有属性定义
        public string Name
        {
            get //get访问器
            {
                return name;
            }
            set //set访问器
            {
                name = value; //value是隐式参数
            }
        }
        
    }
}

当然啦,你也可以不使用属性来表示,替换办法如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp
{
    class Person
    {
        private string name; //私有字段定义
        
        public string getName() //返回字段
        {
            return name;
        }
        
        public void setName(string value) //为字段赋值
        {
            name = value;
        }
        
    }
}

在不使用属性的情况下,只能通过定义两个方法来对字段进行访问,是不是比较麻烦啊。C#为了使字段的访问过程更加简单,提出了属性的概念,通过操作属性来访问字段,避免了调用方法。

上面我们介绍的是可读可写属性可读可写属性同时包含get访问器和set访问器),下面介绍一下只读属性只写属性当属性仅包含get访问器,或set访问器为private级别时,这样的属性称为只读属性当属性仅包含set访问器,或get访问器为private级别时,这样的属性称为只写属性

代码实例:

private string name; //私有字段定义

//只读属性定义方法一:
public string Name
{
    get //get访问器
    {
        return name;
    }          
}
private string name; //私有字段定义

//只读属性定义方法二:
public string Name
{
    get //get访问器
    {
        return name;
    }
    private set //set访问器
    {
        name = value; //value是隐式参数
    }
}
private string name; //私有字段定义

//只写属性定义方法一:
public string Name
{
    set //set访问器
    {
        name = value; //value是隐式参数
    }
}
private string name; //私有字段定义

//只写属性定义方法二:
public string Name
{
    private get //get访问器
    {
        return name;
    }
    set //set访问器
    {
        name = value; //value是隐式参数
    }
}

属性除了能直接访问私有字段外,还可以根据需要加入更多的逻辑控制代码。

代码示例:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp
{
    class Person
    {
        private string _name;       
        private int _age;
        private char _gender;
        
        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }
        
        public int Age
        {
            get { return _age; }
            //在赋值的时候,对字段进行限定,如果用户输入的年龄为负数或大于100,则默认赋值为0
            set
            {
                if (value < 0 || value > 100)
                {
                    value = 0;
                }
                _age = value;
            }
        }
        
        public char Gender
        {
            //在访问取值的时候,对字段进行限定,如果用户输入的性别不是男或女,则默认赋值男,再返回
            get
            {
                if (_gender != '男' || _gender != '女')
                {
                    _gender = '男';
                }
                return _gender;
            }
            set { _gender = value; }
        }
               
    }
}

和静态字段类似,属性也可以通过static关键字声明为静态属性,此时的静态属性属于类级别,不能通过类的实例进行访问,也不能在静态属性中使用非静态的字段。

静态属性定义代码示例:

private static string _name; 
      
public static string Name
{
    get { return _name; }
    set { _name = value; }
}

普通属性代码还是很多写起来还是很麻烦怎么办?不急还有更简便的方法,下面来介绍自动属性,自动属性是C# 5.0(含)之后,微软新增的语法糖,全称为 Auto-Implemented Properties。如果属性的get和set访问器中没有任何逻辑,就可以使用自动实现的属性。不需要声明私有化字段。编译器会自动创建它。

自动属性格式:

public 数据类型 属性名 { get; set; } //取值方法和赋值方法可以指定不同的访问权限

快速生成自动属性的方法:键入“prop”连按两次“Tab”,自动生成后再修改成需要的数据类型和属性名。

快速自动生成公开读,私有写属性的方法: 键入“propg”连续两次“Tab”,自动生成后再修改成需要的数据类型和属性名。

自动属性和普通属性的区别:

1、普通属性有私有字段和方法体。

2、自动属性不能有方法体,和私有字段。

3、本质上自动属性和普通属性没有区别。

自动属性代码示例:

public string Name { get; set; }


类的实例化

当写好了一个类后,我们需要创建这个类的对象,创建这个类的对象的过程,我们称之为类的实例化,使用new关键字 。实例化就是创建一个对象的过程,对象就是类的实例。注意:只有包含实例构造函数的类才能被实例化,而在静态类中是不能定义实例构造函数的。

代码示例:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            Person p = new Person(); //创建Person类的对象,创建这个类的对象的过程,就是类是实例化
            //当我们创建好一个类的对象后,需要给这个对象的每个属性去赋值,这个过程称之为对象的初始化。
            p.Name = "张三";
            p.Gender = '人';
            p.Age = -360;
            p.Tel = "13888888888";
            p.Print();
            Console.ReadKey();
        }
    }
}

Person类代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp
{
    class Person
    {
        private string _name;
        private char _gender;
        private int _age;
        
        //使用了普通属性
        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }
        
        //使用了自动属性
        public string Tel { get; set; }
        
        public char Gender
        {
            //在访问取值的时候,对字段进行限定,如果用户输入的性别不是男或女,则默认赋值男,再返回
            get
            {
                if (_gender != '男' || _gender != '女')
                {
                    _gender = '男';
                }
                return _gender;
            }
            set { _gender = value; }
        }
        
        public int Age
        {
            get { return _age; }
            //在赋值的时候,对字段进行限定,如果用户输入的年龄为负数或大于100,则默认赋值为0
            set
            {
                if (value < 0 || value > 100)
                {
                    value = 0;
                }
                _age = value;
            }
        }
        
        public void Print()
        {
            Console.WriteLine("姓名:{0},性别:{1},年龄:{2},电话:{3}", this.Name, this.Gender, this.Age,this.Tel); //this:表示当前这个类的对象
        }
        
    }
}

运行结果:

image.png




暗锚,解决锚点偏移

文章评论

    嘿,来试试登录吧!