《随笔七》——C#中的 “ 属性 、 静态属性 ”

目录

属性

使用属性

利用 set 和 get  访问器 执行其它运算

只读和只写属性

属性和公共字段

自动实现属性

静态属性


属性


  属性是代表类的实例或类中的一个数据项的成员。属性指的是一组两个匹配的、称为访问器的方法:

public  返回类型  标识符
{
  set 访问器为属性赋值
  get 访问器为属性获取值
}
  • 注意: public 这样的修饰符是可选的,可以选择私有的,这样就不可以在类外直接访问 set 和 get 访问器了。但是间接 的。
  • 注意: 访问器不能被直接调用。

set访问器总是:

  • 拥有一个单独的、隐式的值参,名称为value, 其类型与属性的相同。
  • set 访问器返回类型为void

 get访问器总是:

  • 没有参数。
  • 拥有一个与属性类型相同的返回类型。属性返回的类型要跟你要返回的字段的返回类型相同。

  属性跟字段的相同点:

  • 它是命名的实例成员
  • 它有类型
  • 它可以被赋值和读取。

 属性跟字段的不相同点:

  •  属性属于一个成员函数
  • 它不为数据存储分配内存
  • 它执行代码

访问器的重点如下:

  • get 访问器的所有执行路径都必须包含一条return 语句,返回一个属性类型的值。
  • 访问器 set 和 get 可以任何顺序声明, 并且只能有这两个方法,不能有其他的。
     
  • 要想不定义属性的某个访问器,可以忽略该访问器的声明。
  • 两个访问器中至少有一个必须定义, 否则编译器会产生错误信息。
  • 属性它是本身是没有任何存储的,并且它可以被声明为  static。

使用属性


  写入和读取属性的访问器时,会被隐式调用:

  • 要写入一个属性,在赋值语句的左边使用属性的名称。
  • 要读取一个属性,把属性的名称用在表达式中。

注意: 不能显式地调用访问器,就跟调用函数那样, 会出现编译错误。


namespace Ch05Ex03
{
    class D  // 属性本身不分配内存
    {
        private double name = 3.14;  // 为字段分配内存
        public double MyValue   
        {
            set
            {
                name = value; //返回类型为void
            }
            get
            {
                return name;  // 返回类型是属性的类型,属性的类型也要跟字段的数据类型一致
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            D myD = new D();
            myD.MyValue = 5.666;  //给访问器中的字段赋值
            WriteLine(myD.MyValue);  //输出赋值后的字段的值

            var tmp = myD.MyValue; 
            WriteLine(tmp);  //输出赋值后的字段的值

            var tt = myD.get(); // 错误, 不能这样显式调用
            myD.set(5.3); // 错误, 不能这样显式调用
            ReadKey();
        }
    }
}

我们经常将类中的字段声明private以封装该字段, 然后声明一个public的属性来控制从类的外部对该字段的访问。和属性关联的字段称为后备字段或后备存储。

 属性和后备字段需要注意的问题有:

  • 一种约定是两个名称使用相同的内容, 但字段使用Camel 大小写, 属性使用 Pascal 大小写。
  • 另一种是字段使用Camel 大小写,并以下划线开始,属性使用 Pascal 大小写。
         private  double nameField = 3.14; //第一种约定
        public double NameFild
        {
            set
            {
                nameField = value;
            }
            get
            {
                return nameField;
            }
        }
 private  double _nameField = 3.14;  // 第二种约定
        public double NameFild
        {
            set
            {
                _nameField = value;
            }
            get
            {
                return _nameField;
            }
        }

利用 set 和 get  访问器 执行其它运算


属性访问器不仅仅只可以对关联的字段传入传出数据, 还可以执行任何计算,或者不执行任何计算。但是get访问器必须返回一个属性类型的值。

 

下面看一个更有用的示例:

namespace Ch05Ex03
{
    class D
    {
        private  double _nameField = 3.14;
        public double NameFild
        {
            set
            {
                _nameField = value > 100 ? 100 : value;  //执行计算
            }
            get
            {
                return _nameField;
            }
        }
    }
  
    class Program
    {
        static void Main(string[] args)
        {
            D myD = new D();
            myD.NameFild = 200;  //给访问器中的字段赋值
            WriteLine(myD.NameFild);  //输出赋值后的字段的值
            ReadKey();
        }
    }
}
 

只读和只写属性


  •  要想不定义属性的某个访问器, 可以忽略该访问器的声明。
  •   只有get访问器的属性是只读属性。它是安全的, 只传出数据。
  •   只有set访问器属性是只写属性, 它是安全的, 把一项数据从类的外部传入类, 而不允许太多访问方法。

使用属性比使用公共字段更好


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

  • 因为属性是函数成员,而不是数据成员,因此它们允许您处理输入和输出,而公共字段则无法处理。
  • 属性可以只读或只写,而字段不行。
  • 编译后的变量和属性语义不同。

自动实现属性


 自动实现属性: 允许只声明属性而不声明后备字段。 编译器会为你创建隐藏的后备字段, 并且自动挂接到get 和 set 访问器上。

自动实现属性的要点如下:

  • 不声明后备字段—— 编译器根据属性的类型分配存储。
  • 不能提供访问器的方法体—— 它们必须被简单地声明为分号。 get 相当于简单的内存读, set 相当于简单的内存写。
  • 除非通过访问器,否则不能访问后备字段。 因为不能用其他的方法访问它, 所以单独实现某个只读或只写属性没有意义, 因此必须同时提供读写访问器。
  • 自动实现的属性它本身会分配内存。
namespace Ch05Ex03
{
    class D
    {
     
        public double NameFild  //分配内存
        {
            set;get;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            D myD = new D();
            myD.NameFild = 200;  //给访问器中的字段赋值
            WriteLine(myD.NameFild);  //输出赋值后的字段的值
            ReadKey();
        }
    }
}
 

除了方便之外,自动实现的属性还允许您轻松地插入一个属性,本来那里您可能想要声明一个公共字段的。


静态属性


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

  • 不能访问类的实例成员,但是可以访问类的静态实例成员; 但是静态属性能被实例成员所访问。
  • 不管类是否有实例,它们都是存在。
  • 当从类的外部访问时,必需使用类名引用,而不是实例名。
namespace Ch05Ex03
{
    class D
    {
        public static int MyValue
        {
            get; set;
        }
        public void PrintValue()
        {
            WriteLine($"输出值为:{MyValue}");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            WriteLine($"先输出静态属性的值:{D.MyValue}");
            D.MyValue = 10;  // 在类的外部设置静态属性的值
            WriteLine($"再输出静态属性的值:{D.MyValue}");
            ReadKey();
        }
    }
}


再看一个示例程序:

namespace Ch05Ex03
{
    class D
    {
        int aa = 12;
        static int bb;
       public static void Show()
        {
            WriteLine($"输出bb的值:{bb}");
            //WriteLine($"输出bb的值:{aa}");  错误,静态成员函数不可以输出非静态成员数据
        }
        public void PrintValue()
        {
            WriteLine($"输出bb的值:{bb}"); // 非静态的成员函数可以输出静态字段的值
            WriteLine($"输出aa的值:{aa}");
        }
        public static int MyValue
        {
             set
            {
                //aa = value; //错误,静态属性不可以访问非静态字段
                bb = value; //正确,静态属性可以访问静态字段
            }
            get
            {
                return bb;
            }
        }
      
    }

    class Program
    {
        static void Main(string[] args)
        {
            WriteLine($"先输出静态属性的值:{D.MyValue}");
            D.MyValue = 100;  // 在类的外部设置静态属性的值
            WriteLine($"再输出静态属性的值:{D.MyValue}");

            D myD = new D();  
            myD.PrintValue();
            ReadKey();
        }
    }
}

输出结果为:

先输出静态属性的值:0
再输出静态属性的值:100
输出bb的值:100
输出aa的值:12

 

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值