目录

1、字段

2、注意事项:

3、属性

4、什么是索引器

5、什么是常量

1、字段

什么是字段

  • 字段(field)是一种表示与对象或类型(类与结构体)关联的变量的成员
  • 字段是类型的成员,旧称“成员变量”
  • 与对象关联的字段称为“实例字段”
  • 与类型关联的字段称为“静态字段”,由static修饰

字段的声明

  • 尽管字段声明带有分号,但它不是语句。
  • 字段的名字一定是个名词。

字段的初始值

  • 无显示初始化时,字段获得其类型的默认值,所以字段“永远都不会未被初始化”
  • 实例字段初始化的时机-----对象创建时
  • 静态字段初始化的时机-----类型被加载时(load)

只读字段

  • 实例只读字段
  • 静态只读字段

字段是定义在方法外面的变量,是成员变量,主要是为了类的内部数据交换使用,字段一般是用private修饰,也可以用readonly修饰,表示只读字段,其他修饰符比较少用,字段是用来存储数据的。

字段声明的格式:[访问修饰符]数据类型 字段名 = [初始值]

例如:private string MyName = string.empty;

属性可以理解为对数据的存储,是一种方法,是字段的封装(字段才是对数据的保存单元),一般对外提供访问,可以添加需要的逻辑,属性一般都是用public进行修饰。

总结:属性可以说是字段的扩展,字段是存储数据的单元,而属性本身不存储数据,可以说是对数据的操作,拥有自己的业务逻辑,获取数据,对数据处理,返回处理后的数据等。

属性的定义是get访问器和set访问器组成,get访问器就是对字段值进行读取,而set访问器就是对字段进行赋值,就是对字段操作的两个方法。

2、注意事项:

(1)定义属性时,类型必须与它所访问的字段类型一致。

(2)一般情况下,字段的名称是小写的,属性的名称与字段名称一样,只是首字母要大写。属性的类型定义属性,我们可以给他设定值,也可以获取它的值。如果想保护属性关联的字段,则只允许读数据,或者只允许写数据,

那么应该如何设定呢?

属性除了可以约束数据访问外,还可以设定设置读写属性,来限定它的访问类型,我们可以设置该属性为只读属性,这种情况下,我们就只能读取字段的值而不能赋值,属性的访问分类为以下三种:

---只读属性,只包含get访问器

---只写属性,只包含set访问器

---读写属性,包含get和set访问器

get和set访问器的灵活运用,可以保障类中字段的安全。

using System;
namespace 字段2
{    
    class Program
    {
        static void Main(string[] args)
        {
            System.Console.OutputEncoding = System.Text.Encoding.UTF8;
            #region 字段和属性
            /*
            //C1初始化实例
            C1 c1 = new C1();
            //把属性看做一个字段,从中读取它的值;
            Console.WriteLine("realValue:{0}", c1.RealValue);
            //通过set访问器进行赋值
            c1.RealValue = 25;
            Console.WriteLine("realValue:{0}",c1.RealValue);  
            Console.WriteLine();
            //C2初始化实例
            C2 c2 = new C2();
            Console.WriteLine("属性值:{0}", c2.RealValue);
            //赋值
            c2.RealValue = 47;
            Console.WriteLine("属性值:{0}", c2.RealValue);
            Console.WriteLine();
            */
            #endregion
            #region 属性不与字段关联
            /*
            //Triangle初始化实例
            Triangle tri = new Triangle();
            Console.WriteLine("三角形第三边长度:{0}",tri.GetThird);
            //进行赋值
            tri.a = 50;
            tri.b = 40;
            Console.WriteLine("三角形第三边长度:{0}", tri.GetThird);
            Console.WriteLine();
             */
            #endregion
            #region Person传值
            //输出姓名,年龄
            //初始化实例
            Person son = new Person();
            //通过方法给字段赋值
            son.SetName("天天");
            //通过属性给字段赋值
            son.Age = 5;
            son.print();
            #endregion
            #region 初始化实例输出手机信息
            MyPhone1 phone = new MyPhone1();
            phone.PhoneID = 888;
            phone.PhoneName = "华为至尊旗舰手机";
            phone.PhonePrice = 9999999;
            phone.OnLine = Convert.ToDateTime("2016-08-20");
            Console.WriteLine("手机编号为:{0}",phone.PhoneID);
            Console.WriteLine("手机名称为:{0}", phone.PhoneName);
            Console.WriteLine("手机价格为:{0}", phone.PhonePrice);
            Console.WriteLine("手机上线日期为:{0}", phone.OnLine);
            //因为是只读属性所以不能进行赋值
            Console.WriteLine("手机销售年限为:{0}", phone.SellYears);
            #endregion
            #region 属性、用户注册登录实验
            User user = new User();
            Console.WriteLine("=========用户注册=========");
            Console.Write("请输入用户名:");
            user.Login = Console.ReadLine();
            Console.Write("请输入密码:");
            user.Password = Console.ReadLine();
            Console.Write("请输入性别:");
            user.Danger = Console.ReadLine();
            Console.WriteLine("=========用户信息=========");
            user.DisPlayinfo();
            #endregion
            Console.ReadKey();
        }
    }
    #region 字段和属性
    /// <summary>
    /// 字段与属性都是类的成员。字段是数据成员,是隶属于类的变量。
    ///属性是函数成员,它不为数据存储分配内寸,它执行代码。
    /// </summary>
    class C1
    {
        private int realValue;  //分配内存
        public int RealValue    //不分配内存
        {
            //get访问器必须包含return语句,返回字段realValue
            get   //只读字段
            {
                return realValue;
            }
            //set访问器接受它的输入参数--value,并将它赋给字段,value是隐式参数
            set  //只写字段
            {
                realValue = value;
            }
        }
    }
    /// <summary>
    /// 自动实现属性,C#允许只声明属性而不声明后续字段,编译器会创建隐藏的后备字段,
    /// 并且自动挂载到get,set访问器上
    /// </summary>
    class C2
    {
        //分配内存
        public int RealValue
        {
            get;
            set;
        }
    }
    #endregion
    #region 属性也可以不与字段关联
    class Triangle
    {
        public double a = 20;
        public double b = 40;
        public double GetThird
        {
            //只读
            get  
            {
                return Math.Sqrt((a+a)*(b+b));
            }
        }
    }
    #endregion
    #region 输出传值
    class Person
    {
        private string name;
        //定义Getname的方法
        public string GetName()
        {
            return name;
        }
        //定义Setname方法,显示定义value参数
        public void SetName(string value)
        {
            this.name = value;
        }
        private int age;
        public int Age //属性
        {
            private get
            {
                return age;
            }
            set
            {
                if (value<0||value>120)
                {
                    Console.WriteLine("输入的年龄无效,请重输入!");
                }
                else
                {
                    this.age = value;
                }
            }
        }
        //输出方法
        public void print()
        {
            Console.WriteLine("name:{0},age={1}",name,age);
        }
    }
    #endregion
    #region 手机类、手机编号、手机名称、手机价格、上线日期、销售年期
    /*
    public  class MyPhone
    {
        //定义一组手机数据 
        private int phoneID;
        private string phoneName;
        private int phonePrice;
        private DateTime onLine;
        private readonly int sellYears;
    }
    */
    public class MyPhone1
    {
        //私有字段,公有属性
        private int phoneID;
        //定义手机ID\PhoneID
        public int PhoneID
        {
            get{return phoneID;}
            set
            {
                if (value <0)
                {
                    phoneID = 1000;
                }
                else
                {
                    phoneID = value;
                }
            }
        }
        //定义手机名字phoneName
        private string phoneName;
        public string PhoneName
        {
            get { return phoneName; }
            set { phoneName = value; }
        }
        //定义手机价格phonePrice
        private int phonePrice;
        public int PhonePrice
        {
            get { return phonePrice; }
            set { phonePrice = value; }
        }
        //上线日期
        private DateTime onLine;
        public DateTime OnLine
        {
            get { return onLine; }
            set { onLine = value; }
        }
        //销售年期
        private int sellYears;
        public int SellYears
        {
            //设置为只读属性
            get { return DateTime.Now.Year - onLine.Year-1; }
            
        }
    }
    #endregion

    #region C#属性的应用1、打个比方我们有个网站,每当有新用户注册的时候,我们需要记录这些用户的信息。创建一个User类来记录用户的注册信息,包括用成员变量(字段)用户名,密码,性别。
    ///2、用属性封装3个字段,实现赋值规则用户名只能以字母开头,密码长度不小于6(默认6个1),性别只能是“男”或“女”。
    /// 3、为User类添加公共的DisplayInfo方法4、在主方法中让用户注册信息,用User对象记录,然后调用对象的DisplayInfo方法显示注册信息。
    class User
    {
        //定义账号,密码,性别
        string login;
        string password;
        string danger;
        //定义账号
        public string Login
        {
            get { return login; }
            set
            {
                //进行判断
                if (char.IsLetter(value,0))
                {
                     login = value;
                }
                else
                {
                    Console.WriteLine("用户名非法,必须以字母开头!");
                    Console.WriteLine("用户名默认为abc");
                    login = "abc";
                }
            }
        } 
        //定义密码
        public string Password
        {
            get { return password; }
            set
            {
                if (value.Length>=8)
                {
                    password = value;
                }
                else
                {
                    Console.WriteLine("密码长度不安全,密码长度应不小于8位");
                    Console.WriteLine("密码已经重新默认为11111111,请尽快进行更改!");
                    password = "11111111";
                }
            }
        }
        //定义性别
        public string Danger
        {
            get { return danger; }
            set
            {
                if (value =="男"||value=="女")
                {
                    danger= value;
                }
                else
                {
                    Console.WriteLine("性别必须为'男'或'女',请重新输入!");
                    Console.WriteLine("性别默认男,请尽快进行更改!");
                    danger = "男";
                }
            }
        }
        //输出信息方法
        public  void DisPlayinfo()
        {
            Console.WriteLine("用户名:{0}", Login);
            Console.WriteLine("密码:{0}", password);
            Console.WriteLine("性别:{0}", danger);
        }

    }
    #endregion
}

3、属性

什么是属性

  • 属性是字段的一种扩展
  • 属性(property)是一种用于访问对象或类型的特征的成员,特征反映了状态。
  • 属性是字段的自然扩展
  • 从命名来看,field更偏向于实例对象在内存中的布局,property更偏向于反映现实世界对象的特征
  • 对外:暴露数据,数据可以存在字段里,也是可以动态计算出来的,
  • 对内:保护字段不被非法值“污染”
  • 属性由Get/Set方法对进化而来

属性的声明

  • 完整声明——后台(back)成员变量与访问器(注意使用code snippet和refactor工具)
  • 简略声明——只有访问器(查看IL代码)
  • 动态计算值的属性
  • 注意实例属性和静态属性
  • 属性的名字一定是名词
  • 只读属性——只有getter没有setter

尽管语法上正确,几乎没有人使用“只读属性”,因为属性的主要目的是通过向外暴露数据而表示对象/类型的状态

属性与字段的关系

  • 一般情况下,他们都是用来表示实体(对象或类型)的状态
  • 属性大多数情况下是字段的包容器(wrapper)
  • 建议:永远使用属性(而不是字段)来暴露数据,即字段永远都是private或者protected的

属性property是一种用于访问对象或类的特征的成员。属性的示例包括字符串的长度、字体的大小、窗口的标题、客户的名称等等。属性是字段的自然扩展,此两者都是具有关联类型的命名成员,而且访问字段和属性的语法是相同的。然而,与字段不同,属性不表示存储位置。相反,属性有访问器(accessor),这些访问器指定在它们的值被读取或写入时需要执行的语句。因此属性提供了一种机制,它把读取和写入对象的某些特征与一些操作相关联起来,甚至它还可以对此类特性进行计算。

using System;
namespace 属性
{
    class Program
    {
        static void Main(string[] args)
        {
            /*
            //计算三个学生的平均年龄
            Student stu1 = new Student();
            stu1.Age = 20;
            Student stu2 = new Student();
            stu1.Age = 20;
            Student stu3 = new Student();
            stu1.Age = 20;
            int avgAge = (stu1.Age+stu2.Age+stu3.Age)/3;
            Console.WriteLine(avgAge);
            Student s1 = new Student();
            s1.SetAge(30);
            Student s2 = new Student();
            s2.SetAge(30);
            Student s3 = new Student();
            s3.SetAge(30);
            //当数值大于120时出现异常
            //Student s3 = new Student();
            //s3.SetAge(30);
            int avgAge1 = (s1.GetAge() + s2.GetAge() + s3.GetAge()) / 3;
            Console.WriteLine(avgAge1);
            */
            //使用try catch来进行检测
            //保护字段的方法
            /*
            try
            {
                Student s1 = new Student();
                s1.SetAge(30);
                Student s2 = new Student();
                s2.SetAge(30);
                //异常输入,输出Age value has erroe!
                Student s3 = new Student();
                s3.SetAge(300);
                int avgAge1 = (s1.GetAge() + s2.GetAge() + s3.GetAge()) / 3;
                Console.WriteLine(avgAge1);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            //使用get和set语句之后可以写回原来的形式,因为有保护措施
            try
            {
                Student s1 = new Student();
                s1.Age = 20;
                Student s2 = new Student();
                s2.Age = 20;
                Student s3 = new Student();
                s3.Age = 20;
                int avgAge2 = (s1.Age + s2.Age+ s3.Age) / 3;
                Console.WriteLine(avgAge2);
            }
            catch (Exception ex)
           {
                Console.WriteLine(ex.Message);
            }
            */
           Console.ReadKey();
        }
    }
    class Student
    {
        //public int Age;
        //私有字段
        private int age;
        //使用属性
        public int Age
        {
            get
            {
                return this.age;
            }
            set
            {
                if (value >= 0 && value <= 120)//value在set上下文中是关键字
                {
                    this.age = value;
                }
                else
                {
                    throw new Exception("Age value has erroe!");
                }
            }
        }
        //获取字段的值的方法
        public int GetAge()
        {
            return this.age;
        }
        //为字段设置值的方法进行保护
        public void SetAge(int value)
        {
            if (value >= 0 && value <= 120)
            {
                this.age = value;
            }
            else
            {
                //抛出异常
                throw new Exception("Age value has erroe!");
            }
        }
    }

}

4、什么是索引器

  • 索引器(indexer)是这样一种成员:它使对象能够用与数组相同的方式(即使用下标)进行索引
  • 索引器的声明
  • 注意没有静态索引器

5、什么是常量

  • 常量(constant)是表示常量值(即,可以在编译时计算的值)的类成员
  • 常量隶属于类型而不是对象,即没有”实例常量“
  • 实例常量的角色由只读实例字段来担当
  • 主要区分成员常量与局部常量

常量的声明

各种只读的应用场景

  • 为了提高程序可读性和执行效率——常量
  • 为了防止对象的值被改变——只读字段
  • 向外暴露不允许修改的数据——只读属性(静态或非静态),功能与常量有一些重叠
  • 当希望成为常量的值其类型不能被常量声明接受时(类/自定义结构体)——静态只读字段
using System;
namespace 索引器和常量
{
    class Program
    {
        static void Main(string[] args)
        {
            /*
            Student stu = new Student();
            stu["Math"] = 90;
            var mathScore = stu["Math"];
            */
            const int x = 100;
            Console.WriteLine(MyClass.WebsiteURL);
            Console.ReadKey();
        }
        static double GetArea(double r)
        {
            double a = Math.PI * r * r;
            return a;
        }
    }
    class MyClass
    {
        public const string WebsiteURL = "http://www.waspec.rog";
        public static readonly Building location = new Building("Some Address") { };
    }
    class Building
    {
        public Building(string address)
        {
            this.Address = address;
        }
        public string Address { get; set; }
    }
    class Student
    {
        /*
        private Dictionary<string, int> scoreDictory = new Dictionary<string, int>();
        /// <summary>
        /// 索引器一般用于集合类型
        /// </summary>
        /// <param name="indexer"></param>
        /// <returns></returns>
        public int? this[string subject]
        {
            get
            {
                if (this.scoreDictory.ContainsKey(subject))
                {
                    return this.scoreDictory(subject);
                }
                else
                {
                    return null;
                }
            }
            set
            {
                if (value.HasValue==false)
                {
                    throw new Exception("Error");
                }
                if (this.scoreDictory.ContainsKey(subject))
                {
                    this.scoreDictory(subject) = value.Value;
                }
                else
                {
                    this.scoreDictory.Add(subject, value.Value);
                }
            
            }
        }
        */
    }
}