C#学习 - 字段、属性、索引器、常量

字段、属性、索引器、常量都是用来表达数据的
C#的类和结构体可能会有如下成员:常量、字段、方法、属性、索引器、事件、运算符、构造函数、析构函数、类型

字段(field)

字段是一种表示与对象或类型(类与结构体)相关联的变量,字段是类型的成员
字段是为一个对象或类型存储数据,字段的值可以表现这个对象或类型当前的状态。字段旧称是“成员变量”

  • 与对象关联的字段称为“实例对象”
internal class Program
{
    static void Main(string[] args)
    {
        People p1 = new People();
        p1.Age = 20;
    }
}
class People
{
    public int Age;//实例字段
}
  • 与类型关联的字段称为“静态字段”,由static修饰
internal class Program
{
    static void Main(string[] args)
    {
        People p1 = new People();
        p1.Age = 20;
        People.PeoNum();
    }
}
class People
{
    public int Age;
    public static int Num;//静态字段,记录人数
    public People()
    {
        People.Num++;
    }
    public static void PeoNum()
    {
        Console.WriteLine(People.Num);
    }
}

注:字段的名字一定是一个名词

声明字段

字段的声明要在类型里面
特性(可删除) + 修饰符组合(需要有意义,可删除) + 字段的数据类型 + 变量声明器(可删除) + “;”
字段声明不是一个语句,语句只出现在函数体中,而字段是出现在类型中
字段的默认值就是字段数据类型的默认初始值
字段也可以在构造器中初始化值
实例类型每次都会初始化,静态类型只有在第一次调用时会初始化

  • 实例字段初始化是对象被创建时
  • 静态字段初始化是类型被加载时

只读字段

修饰符中有一个“readonly”(只读),在声明时初始化后无法赋值,静态只读字段可在静态构造器中初始化

internal class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(Brush.DefaultColor.Red);
        Console.WriteLine(Brush.DefaultSize);
    }
}
struct Color
{
    public int Red;
    public int Green;
    public int Blue;
}
class Brush
{
    public static readonly Color DefaultColor = new Color() { Blue = 0, Green = 0, Red = 0 };
    public static readonly int DefaultSize;
    static Brush()//静态构造器
    {
        Brush.DefaultSize = 5;
    }
}

属性(property)

用于访问对象或类型的特征的成员,特征反映了状态
属性是字段的自然拓展

  • 字段更偏向于实例对象在内存中的布局;属性更偏向于反映现实世界对象的特征
  • 数据存储在字段中时,数据的状态由字段中存储的值而定;属性可以实时动态地计算出数据的特征
  • 字段存储的值可能是错误的(被非法值污染),而属性可以通过一些逻辑保护字段不被非法值污染
  • 建议永远使用属性来向外暴露数据,字段永远用 private 或 protected 修饰
    属性是由Get/Set方法进化而来
internal class Program
{
    static void Main(string[] args)
    {
        People p1 = new People();
        p1.Age = 1000;//对于人的年龄来说,1000就是个非法值
        //而字段就可能被非法值污染
    }
}
class People
{
    public int Age;
}

Get/Set方法:

internal class Program
{
    static void Main(string[] args)
    {
        try
        {
            People p1 = new People();
            p1.SetAge(20);
            People p2 = new People();
            p2.SetAge(250);//250是非法值
            int avgAge = (p1.GetAge() + p2.GetAge()) / 2;
            Console.WriteLine(avgAge);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }
}
class People
{
    private int age;//字段变成private时,使用驼峰法命名
    //使用一对方法保护这个字段。一个方法用来获取这个字段的值;一个为这个字段设置值
    public int GetAge()//获取值
    {
        return age;
    }
    public void SetAge(int value)//设置值
    {
        if (value >= 0 && value <= 120)
        {
            age = value;
        }
        else
        {
            throw new Exception("Age value has error.");
        }
    }
}

属性:

internal class Program
{
    static void Main(string[] args)
    {
        try
        {
            People p1 = new People();
            p1.Age = 20;
            People p2 = new People();
            p2.Age = 25;
            int avgAge = (p1.Age + p2.Age) / 2;
            Console.WriteLine(avgAge);
        }
        catch (Exception error)
        {
            Console.WriteLine(error.Message);
        }
    }
}
class People
{
    private int age;
    public int Age//Age属性
    {
        //括号内为访问器
        get//获取值
        {
            return age;
        }
        set//设置值
        {
            if(value >=0&&value<=120)//C#中准备了一个默认的变量value
            {//value是上下文关键字,在某个特定的代码上下文中其是关键字
                age = value;
            }
            else
            {
                throw new Exception("Age value has error.");
            }
        }
    }
}

属性是一种“语法糖”,上段代码中的get和set会自动调用get_Age()和set_Age(int32)

属性的声明

注:属性名字需要是名词或名词短语
属性有完整声明和简略声明,区别主要是 get 和 set 的使用

  • 完整的声明
    特性(可删除) + 修饰符组合(需要有意义,可删除) + 属性的数据类型 + 属性的名字 + { get 和 set }
private int myVar;
public int MyProperty
{
    get { return myVar; }
    set { myVar = value; }
}

如果一个属性只有 get 没有 set 则是只读属性;而如果一个属性只有 set 没有 get 则是只写属性
VS中输入propfull+敲击两下tab就能自动出现完整的声明
使用静态属性时,对应保护的字段也需要被static修饰

  • 简略的声明
    简略的属性声明与字段类似,不受保护,可能会被非法值污染
public int MyProperty { get; set; }

VS中输入prop+敲击两下tab就能自动出现完整的声明
简略声明会在后台封装一个私有变量

  • 重构声明
    输入一个私有字段,光标置于字段上,Ctrl+R -> Ctrl+E

只读属性

只读属性只有get,没有set

private int myVar;
public int MyProperty
{
    get { return myVar; }
}

还有一类特殊的“只读”属性,是外界无法访问 set 方法,只能在内部使用 set

private int myVar;
public int MyProperty
{
    get { return myVar; }
    private set { myVar = value; }
}
public void MethodSet()
{
	MyProperty = 10;
}

动态计算值

internal class Program
{
    static void Main(string[] args)
    {
        People p1 = new People();
        p1.Age = 15;
        Console.WriteLine(p1.CanWork);
    }
}
class People
{
    private int age;

    public int Age
    {
        get { return age; }
        set { age = value; }
    }
    public bool CanWork
    { //这里的 CanWork 就是动态计算的属性
        get
        {
            if (age >= 16)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    }
}

索引器(indexer)

索引器能使对象能够用以数组相同的方法进行索引(即是使用下标)
一般有索引器这个成员的类是集合类型
VS中输入indexer+敲击两下tab就能自动出现索引器
索引器应用于非集合类型:

internal class Program
{
    static void Main(string[] args)
    {
        WorkWages wages = new WorkWages();
        wages["Teacher"] = 3000;//为教师工作工资赋值
        var TeacherWages = wages["Teacher"];//获取工资值
        Console.WriteLine(TeacherWages);
    }
}
class WorkWages//用来检测不同工作工资
{                      //键 -- 值
    private Dictionary<string, int> wagesDictinoary = new Dictionary<string, int>();
    public int? this[string work]//索引器
    {
        get 
        {   //若输入的工作存在,则返回工资
            if (wagesDictinoary.ContainsKey(work))
            {
                return wagesDictinoary[work];
            }
            else
            {   //若输入的工作不存在,则返回NULL
                return null;
            }
        }
        set 
        {   //判断用户设定的工资值是否为NULL
            if (value.HasValue == false)
            {   //若为NULL,则报错
                throw new Exception("Wages is null.");
            }
            if (wagesDictinoary.ContainsKey(work))
            {
                wagesDictinoary[work] = value.Value;//value为可空类型
            }                       //可空类型.Value则是这个类型真正的值
            else
            {   //若字典中不存在这个工作,则在字典中加入一条“键和值”
                wagesDictinoary.Add(work, value.Value);
            }
        }
    }
}

常量(constant)

用来表示常量值的类成员,使用常量可以提高程序运行效率
比如Math.PI就是个常量,使用时会用一个常量代替这个标识符
常量需要用 const 修饰
常量隶属于类型而不是对象,即没有“实例常量”,“实例常量”可以用只读字段来代替

  • 成员常量:类的成员中的常量
  • 局部常量:在声明变量时,在前面用 const 修饰
internal class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(NASA.WebURL);//调用成员常量需要使用类型 + . + 常量名称
    }
}
class NASA
{
    public const string WebURL = "https://www.nasa.gov/";
}

各种“只读”作用

  • 常量:提高程序可读性和执行效率
  • 只读字段:防止对象的值被改变
  • 只读属性(静态或非静态):向外暴露不允许修改的数据
  • 静态只读字段:让成为常量的值其类型不能被常量声明接受。比如常量不能接收结构体类型,此时就只能用静态只读字段
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值