C#学习笔记 -- 类的属性

属性

属性代表类实例或类中数据项的成员, 使用属性就像写入或读取一个字段, 语法相同, 从语法上无法区分他们

(0)属性的特征

  • 是命名的类成员

  • 有类型

  • 可以被赋值和读取

  • 与字段不同, 属性是一个函数成员

    • 不一定为数据存储分配内存

    • 执行代码

  • 属性是两个匹配的、命名的、称为访问器的方法,访问器不能直接被调用

    • set访问器给属性赋值

    • get访问器获取属性值

(1)属性声明与访问器

//声明类一个名为MyValue的int类型属性的语法
int MyValue
{
    set
    {
        //SetAccessorCode
    }
    get
    {
        //GetAccessorCode
        return intValue;
    }
}
  • set和get访问器有预订的语法和语义, 而且可以以任何顺序声明, 除了这两个访问器外, 属性上不允许有其他方法

  • 可以把set访问器想象成一个方法, 带有单一的参数, 他设置属性的值

    • set访问器有一个单独的隐式的值参, 名称为value, 与属性的类型相同, 无需再声明参数列表的值参数

    • set访问器返回void

  • get访问器没有参数, 并从属性返回一个值

    • get访问器没有参数

    • 隐式的拥有一个与属性类型相同的返回类型, 无需再声明返回值

    • get访问器的所有执行路径必须包含一条返回语句, 将返回一个属性类型的值

(2)创建属性示例

注意
  1. 属性自己并没有任何存储, 取而代之, 访问器决定如何处理发送进来的数据, 以及将什么数据发送出去,

  2. 属性访问器常常使用字段作为存储

  3. set访问器接受它的输入参数value, 并把它的值赋给字段theRealValue

  4. get访问器只是返回字段的值TheRealValue

class Program710_2
{
    private int theRealValue;
​
    public int MyValue
    {
        set
        {
            theRealValue = value;
        }
        get
        {
            return theRealValue;
        }
    }
}

(3)使用属性

写入和读取属性的方法与访问字段一样, 访问器被隐式调用

  • 要写入一个属性, 在赋值语句的左边使用属性的名称, 不能显式调用set访问器

  • 要读取一个属性, 把属性的名称用在表达式中, 不能显式调用get访问器

class Program710_2
{
    private int theRealValue;
​
    public int MyValue
    {
        set
        {
            theRealValue = value;
        }
        get
        {
            return theRealValue;
        }
    }
​
    //使用属性
    public void UseMyValue()
    {
        MyValue = 5;//设置属性
        int z = MyValue;//读取属性
        Console.WriteLine($"我的属性是: {z}");
    }
}
static void Main(string[] args)
{
    Program710_2 program710_2 = new Program710_2();
    program710_2.UseMyValue(); //5
    program710_2.MyValue = 15;
    int Value = program710_2.MyValue;
     Console.WriteLine($"在main中我的属性是 :{Value}"); //15
}

(4)属性和关联字段

  • 属性常常与字段关联, 一种常见的方式是在类中将字段声明为私有, 以封装该字段

  • 并声明一个public属性来控制从类的外部对该字段的访问

  • 属性关联的字段常常被称为后备字段或后背存储

class Program710_4
{
    private int theRealValue = 10; //后备字段, 分配内存
​
    public int MyValue
    {
        set { theRealValue = value; }
        get { return theRealValue; }
    }
}
static void Main(string[] args)
{
    Program710_4 program710_4 = new Program710_4();
    Console.WriteLine($"类的属性值是: {program710_4.MyValue}");
    program710_4.MyValue = 20;
    Console.WriteLine($"设置类的属性值为: {program710_4.MyValue}");
}
属性和关联字段的命名
  • 第一种命名: 两个名称使用相同的内容, 但是字段小驼峰, 属性大驼峰

    class Program710_4
    {
        private int myValue = 10; //后备字段, 分配内存
    ​
        public int MyValue
        {
            set { myValue = value; }
            get { return myValue; }
        }
    }
  • 第二种命名: 两个名称使用相同内容, 但是字段小驼峰并以下划线开始, 属性大驼峰

    class Program710_4
    {
        private int _myValue = 10; //后备字段, 分配内存
    ​
        public int MyValue
        {
            set { _myValue = value; }
            get { return _myValue; }
        }
    }

(5)执行其他计算

属性访问器不限于对后备字段传入传出数据, 访问器可以进行任何计算, 唯一必须的行为是get访问器要返回一个属性类型的值

private int _myValue = 10;
​
public int MyValue
{
    //如果赋值大于100就设置属性为100否则设置属性为赋值
    set { _myValue = value > 100 ? 100 : value; } 
    get { return _myValue; }
}
}

Lamba表达式

class Progrom710_5
{
    private int _myValue = 10;
​
    public int MyValue
    {
        //如果赋值大于100就设置属性为100否则设置属性为赋值
        set { _myValue = value > 100 ? 100 : value; } 
        get => _myValue;
    }
}

(6)只读和只写属性

想要不定义某个属性的某个访问器, 可以直接忽略该访问器的声明

  • 只有get访问器的属性称为只读属性

    • 能够将安全的将一个数据项从类或类的实例中传出, 而不必让调用者修改属性值

  • 只有set访问器称为只写属性

    • 没有实际用途, 如果想在赋值时触发一个副作用最好调用方法去修改

  • 两个访问器至少有一个需要被定义, 否则报错

(7)属性与公有字段

属性比公有字段更好, 理由如下

  • 属性是函数成员, 而不是数据成员, 允许你处理输入和输出, 而公有字段不行

  • 属性可以只读或只写, 而字段不行

  • 编译后的变量和编译后的属性语义不同

(8)只读属性例子

类RightTrangle表示一个三角形

  • 他有2个公有字段, 分别表示两条直角边的长度, 这两个字段可以被写入和读取

  • 第三条边由属性Hypotenuse表示, 他是一个只读属性, 其返回值基于另外两条边的长度, 没有存储在字段中, 相反他需要根据两条直角边的值计算正确的值

class RightTrangle
{
    public double A;
    public double B;
    public double C
    {
        get { return Math.Sqrt((A * A) + (B * B)); }
    }
}

(9)自动实现属性

因为属性经常被关联到后背字段, 所以提供了自动实现属性, 常简称为“ 自动属性 ”, 允许只声明属性而不声明后背字段, 编译器会为你创建隐藏的后备字段, 并自动挂载到getter、setter

  • 不声明后备字段: 编译器根据属性的类型分配存储

  • 不能提供访问器的方法体: 它必须被简单的声明为分号

    • get担当简单的内存读

    • set担当简单的写

  • 但是因为无法访问自动属性的方法体, 调试代码困难

class Program710_9
{
    public int MyValue
    {
        set; get;
    }
}
Program710_9 program710_9 = new Program710_9();
program710_9.MyValue = 10;
int myValue = program710_9.MyValue;
Console.WriteLine($"使用自动实现属性, 属性为: {myValue}");

(10)静态属性

属性可以声明为static, 静态属性的访问器和所有静态成员一样, 特点如下

  • 不能访问类的实例成员, 但是能被实例成员访问

  • 不管类是否有实例, 他们都是存在的

  • 在类的内部, 可以仅使用名称来引用静态属性

  • 在类的外部, 可以使用类名或using static结构引用静态属性

class Program710_10
{
    public static int MyValue
    {
        set; get;
    }
    //内部调用静态属性
    public void PrintMyValue()
    {
        Console.WriteLine($"内部调用静态属性, 属性值: {MyValue}");
    }
}
static void Main(string[] args)
{
    Program710_10 program710_10 = new Program710_10();
    program710_10.PrintMyValue();
    //传统方式外部访问静态属性
    Program710_10.MyValue = 10;
    int staticValue = Program710_10.MyValue;
    Console.WriteLine($"在类的外部, 传统方法调用静态属性, 属性值为: {staticValue}");
    //使用using static外部访问静态属性
    MyValue = 20;
    int usingStaticValue = MyValue;
    Console.WriteLine($"在类的外部, 使用using static调用静态属性, 属性值为{usingStaticValue}");
}

posted on 2023-05-20 23:48  老菜农  阅读(92)  评论(0编辑  收藏  举报

导航