- 常量 与类关联的常量值
- 字段 类的变量
- 方法 类可执行的计算和操作
- 属性 与读写类的命名属性相关联的操作
- 索引器 与以数组方式索引类的实例相关联的操作
- 事件 可由类生成的通知
- 运算符 类所支持的转换和表达式运算符
- 构造函数 初始化类的实例或类本身所需的操作
- 析构函数 在永久丢弃类的实例之前执行的操作
- 类型 类所声明的嵌套类型
字段
什么是字段
- 字段
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();
}
}
}
- 属性由
get
和set
方法进化而来
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
键,即可快速书写setter
和getter
方法。
属性与字段的关系
- 一般情况下,属性和字段都用于表示实体(对象或类型)的状态
- 属性大多数情况下是字段的包装器
wrapper
- 建议永远使用属性而非字段来暴露数据,即字段永远都是
private
或protected
的。
索引器
什么是索引器
索引器(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();
}
}
}