C#类成员

  • 常量 与类关联的常量值
  • 字段 类的变量
  • 方法 类可执行的计算和操作
  • 属性 与读写类的命名属性相关联的操作
  • 索引器 与以数组方式索引类的实例相关联的操作
  • 事件 可由类生成的通知
  • 运算符 类所支持的转换和表达式运算符
  • 构造函数 初始化类的实例或类本身所需的操作
  • 析构函数 在永久丢弃类的实例之前执行的操作
  • 类型 类所声明的嵌套类型

字段

什么是字段

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

范例:C语言中的成员变量

$ vim field.c
#include 
// 结构体的字段
struct User
{
    int ID;
    char* UserName;
};

void main()
{
    struct User user;
    user.ID = 1;
    user.UserName = "Mr.Okay";
    printf("User #%d is %s", user.ID, user.UserName);
}
$ gcc field.c -o field.exe
$ field.exe
User #1 is Mr.Okay

实例:实例字段
通过静态变量表现实例变量当前的状态

using System;
using System.Collections.Generic;

namespace Test
{
    class User
    {
        //实例字段
        public int Age;
        public int Score;
        //静态字段
        public static int AverageAge;
        public static int AverageScore;
        public static int Amount;
        //构造函数
        public User()
        {
            User.Amount++;
        }
        //静态方法
        public static void ReportAmount()
        {
            Console.WriteLine(User.Amount);
        }
        public static void ReportAge()
        {
            Console.WriteLine(User.AverageAge);
        }
        public static void ReportScore()
        {
            Console.WriteLine(User.AverageScore);
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            List userlist = new List();
            for(int i=0; i<100; i++)
            {
                User user = new User();
                user.Age = i;
                user.Score = i;
                userlist.Add(user);
            }

            int totalAge = 0;
            int totalScore = 0;
            foreach(var user in userlist)
            {
                totalAge += user.Age;
                totalScore += user.Score;
            }

            User.AverageAge = totalAge / User.Amount;
            User.AverageScore = totalScore / User.Amount;

            //静态变量
            User.ReportAmount();
            User.ReportAge();
            User.ReportScore();

            Console.ReadKey();
        }
    }
}

字段的声明

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

字段的初始化

  • 无显式初始化时,字段获得其类型的默认值,所以字段永远不会未被初始化。
  • 实例字段初始化的时机是在对象创建时
  • 静态字段初始化的时机是在类型被加载load

只读字段

  • 实例只读字段
using System;
using System.Collections.Generic;

namespace Test
{
    class User
    {
        //只读实例字段
        public readonly int ID;
        //实例字段
        public int Age;
        public int Score;
        //静态字段
        public static int AverageAge;
        public static int AverageScore;
        public static int Amount;
        //构造函数
        public User(int id)
        {
            this.ID = id;//只读字段只能在实例化时初始化,且不能赋值。
            User.Amount++;
        }
        //静态方法
        public static void ReportAmount()
        {
            Console.WriteLine(User.Amount);
        }
        public static void ReportAge()
        {
            Console.WriteLine(User.AverageAge);
        }
        public static void ReportScore()
        {
            Console.WriteLine(User.AverageScore);
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            List userlist = new List();
            for(int i=0; i<100; i++)
            {
                User user = new User(i);
                user.Age = i;
                user.Score = i;
                userlist.Add(user);
            }

            int totalAge = 0;
            int totalScore = 0;
            foreach(var user in userlist)
            {
                totalAge += user.Age;
                totalScore += user.Score;
            }

            User.AverageAge = totalAge / User.Amount;
            User.AverageScore = totalScore / User.Amount;

            //静态变量
            User.ReportAmount();
            User.ReportAge();
            User.ReportScore();

            Console.ReadKey();
        }
    }
}
  • 静态只读字段
using System;

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

            Console.ReadKey();
        }
    }
}

属性

什么是属性

  • 属性property是一种用于访问对象或类型的特征的成员,特征反映了状态
  • 属性是字段的自然扩展
    从命名上看field字段更加偏向于实例对象在内存中的布局,property属性更加偏向于反映现实世界对象的特征。
    属性对外暴露数据,数据可以是存储在字段里的,也可以是动态计算出来的。
    属性对内则保护字段不被非法值污染
using System;

namespace Test
{
    class User
    {
        private int age;
        public int GetAge()
        {
            return age;
        }
        public void SetAge(int value)
        {
            if(value >= 0 && value <= 120)
            {
                this.age = value;
            }
            else
            {
                throw new Exception("Age value has error");
            }
        }                    
    }
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                User user1 = new User();
                user1.SetAge(20);
                User user2 = new User();
                user2.SetAge(200);
                int avgAge = (user1.GetAge() + user2.GetAge()) / 2;
                Console.WriteLine(avgAge);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

            Console.ReadKey();
        }
    }
}
  • 属性由getset方法进化而来
using System;

namespace Test
{
    class User
    {
        //属性 
        private int age;
        public int Age {
            get
            {
                return this.age;
            }
            set
            {
                if (value >= 0 && value <= 120)
                {
                    this.age = value;
                }
                else
                {
                    throw new Exception("Age value has error");
                }
            }
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                User user1 = new User();
                user1.Age = 20;
                User user2 = new User();
                user2.Age = 200;
                int avgAge = (user1.Age + user2.Age) / 2;
                Console.WriteLine(avgAge);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

            Console.ReadKey();
        }
    }
}
  • 属性背后的秘密

属性的声明

  • 属性完整的声明 - 后台成员变量与访问器
  • 属性简略声明 - 只有访问器
  • 动态计算值的属性
  • 注意实例属性和静态属性
  • 属性的名字一定是名词
  • 只读属性即只有getter而没有setter方法
    尽管语法上正确,几乎没有人使用只写属性,因为属性的主要目的是通过向外暴露数据而表示对象或类型的状态。
using System;

namespace Test
{
    class User
    {
        private static int amount;
        public static int Amount
        {
            get { return amount; }
            set {
                if(value >= 0)
                {
                    User.amount = value;
                }
                else
                {
                    throw new Exception("Amount value is error");
                }
            }
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                User.Amount = 200;
                Console.WriteLine(User.Amount);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

            Console.ReadKey();
        }
    }
}

VS2017中书写属性的,类中键入propfull后连续按两下Tab键,即可快速书写settergetter方法。

属性与字段的关系

  • 一般情况下,属性和字段都用于表示实体(对象或类型)的状态
  • 属性大多数情况下是字段的包装器wrapper
  • 建议永远使用属性而非字段来暴露数据,即字段永远都是privateprotected的。

索引器

什么是索引器
索引器(indexer)是一种成员:使对象能够用与数组相同的方式即是用下标进行索引

索引器的声明
注意:没有静态索引器

using System;
using System.Collections.Generic;

namespace Test
{
    class User
    {
        private Dictionary dict = new Dictionary();
        public int? this[string key]
        {
            get
            {
                if(this.dict.ContainsKey(key))
                {
                    return this.dict[key];
                }
                else
                {
                    return null;
                }
            }
            set
            {
                if (value.HasValue == false)
                {
                    throw new Exception("dict cannot be null");
                }
                else
                {
                    if (this.dict.ContainsKey(key))
                    {
                        this.dict[key] = value.Value;
                    }
                    else
                    {
                        this.dict.Add(key, value.Value);
                    }
                }
            }
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            User user = new User();
            user["ID"] = 1;
            var val = user["ID"];
            Console.WriteLine(val);
            Console.ReadKey();
        }
    }
}

常量

什么是常量

  • 常量constant是表示常量值,即可以在编译时计算的值的类成员。
  • 常量隶属于类型而非对象,即没有实例常量。实例常量的角色由只读实例来担当。
  • 注意区分成员常量与局部常量

常量的声明

using System;

namespace Test
{
    class Web
    {
        public const string URL = "http://www.baidu.com";
    }
    class Program
    {
        static double GetArea(double r)
        {
            return Math.PI * r * r;
        }
        static void Main(string[] args)
        {
            Console.WriteLine(Web.URL);
            Console.ReadKey();
        }
    }
}

各种只读的应用场景

  • 为了提高程序可读性和执行效率 - 常量
  • 为了防止对象的值被改变 - 只读字段
  • 向外暴露不允许修改的数据 - 只读属性(静态或非静态),功能与常量有些重叠。
  • 当希望成为常量的值其类型不能被常量声明接受时(类或自定义结构体) - 静态只读字段
using System;

namespace Test
{
    class Program
    {
        static double GetArea(double r)
        {
            return Math.PI * r * r;
        }
        static void Main(string[] args)
        {
            Console.WriteLine(Int32.MaxValue);
            Console.ReadKey();
        }
    }
}

你可能感兴趣的:(C#类成员)