博客园  :: 首页  :: 新随笔  :: 订阅 订阅  :: 管理

天轰穿C# -vs2010 - 04面向对象的编程之属性【原创】

Posted on 2012-12-27 15:15  天轰穿  阅读(370)  评论(0编辑  收藏  举报

老田:这就需要用属性了。而属性的使用和字段有很大的相似之处。如下例:

    1. 创建Windows桌面应用程序;
    2. 添加类Product,代码如下:

using System;

using System.Text;

 

namespace _4_5_ProductManagr

{

    public class Product

    {

        ///<summary>

        ///商品名   这是VS能够认识的字段的注释方式

        ///</summary>

        private string _name;

        // 价格    这种注释方式VS无法认识,也就无法提供智能提示

        private decimal _price;

        // 颜色

        private string _color;

        ///<summary>

        ///商品名称,可读可写    这是VS能够认识的属性的注释方式

        ///</summary>

        public string Name

        {

            get { return _name; }   //可读

            set { _name = value; }  //可写

        }

        ///<summary>

        ///价格,只写,不允许读

        ///</summary>

        public decimal Price

        {

            set { _price = value; } //可写

        }

        ///<summary>

        ///颜色,只读不可写

        ///</summary>

        public string Color

        {

            get { return _color; }  //可读

        }

    }

}

    1. Form1的界面上做图4-16,这里就不详细讲了,如果你前面的每个示例都清楚命名习惯的话,完全猜得出来

 

                            4-16

    1. 双击“添加”按钮,在按钮中添加代码,使按钮事件代码如下:

        private void button1_Click(object sender, EventArgs e)

        {

            Product pd = new Product(); //实例化 pd 对象

            pd.Name = tb_name.Text;

            pd.Price = decimal.Parse(tb_price.Text);

            pd.Color = tb_Color.Text;       //这行代码出错,为什么?

 

            //添加完成后,填充下面预览的模块

            lbl_name.Text = pd.Name;

            lbl_price.Text = pd.Price.ToString();   //这行代码出错,为什么?

            lbl_color.Text = pd.Color;

        }

    1. 上面代码中因为读写权限导致有两行代码出错,请问如何修正?

小天:多简单啊,在添加的时候先对所有属性进行写操作(set),接着在预览中有全部进行读操作(get)。但是在ProductPrice属性是只写不许读,所以下面预览这里会出错,而Color是只读不许写,所以赋值的时候就出错了。所以要把这个例题修正的话,只需要为PriceColor这两个属性完善读写权限即可。

老田:是的,从上面例题,可以总结出,属性的第一个最大作用就是控制读写权限。这是访问修饰符办不到的。所以我们不会考虑将字段公开来做属性。

属性还有一个重要的特性,代码如下:

        // 商品名

        private string _name;

        ///<summary>

        ///商品名称

        ///</summary>

        public string Name

        {

            get {   //在向用户返回值之前检测

                if (_name == "")

                    return "商品暂无名字";

                else

                    return _name;

            }  

            set {  //在向字段写入值之前检测

                if (value == "")

                    _name = "想骗我?不行的啦!";

                else

                    _name = value;

            }

        }

       小天:这个示例也简单,就是在向类中的数据字段读写值的之前先检查。不过我有点没有看懂,就是这里面的value是哪里来的??

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

       最后一个重要提醒。访问对象的属性,在属性名后面不加括号,访问类中的方法就一定要加括号。例如

            lbl_name.Text = pd.Name;                 //Name是属性

            lbl_price.Text = pd.Price.ToString();   //ToString是方法

 

       小天:我怎么知道谁是属性,谁是方法呢??

       老田:看下图4-17你就明白了。
 

 

                                          4-17

       实现属性还有种办法,如果属性的setget访问器中没有任何逻辑,就可以使用自动实现的属性。这种属性会自动实现基础成员变量。上例的代码如下:

public string Name {get; set;}

小天:你的意思是,使用这种方式则可以不在显示的申明private string _name这个成员变量。编译器会自动创建它。

老田:是的,但是使用自动实现的属性,就不能在属性设置中进行属性的有效性验证。所以在上面的例子中,不能检查_name是否为空。但必须同时设置读写两个访问器。尝试把该属性设置为只读属性,就会出错:

public string Name {get; }

 

但是,每个访问器的访问级别可以不同。因此,下面的代码是合法的:

public string Name {get; private set;}

       小天:通过属性访问字段,而不是直接访问字段。这些额外的函数调用是否会增加系统开销,导致性能下降?

老田:不需要担心这种编程方式会在C#中带来性能损失。C#代码会编译为IL,然后在运行期间进行正常的JIT编译,获得内部可执行代码。JIT编译器可生成高度优化的代码,并在适当的时候内联代码(即用内联代码来替代函数调用)。如果某个方法或属性的执行代码仅是调用另一个方法,或返回一个字段,则该方法或属性肯定是内联的。但要注意,在何处内联代码的决定完全由CLR做出。

本文章为天轰穿原创作品,转载请注明出处及作者。