1.字段
字段是类或结构体中用于存储数据的变量,它是类或结构体的一个成员。字段可以是任何数据类型,包括基本数据类型(如int、double等)、引用类型(如string、自定义类等)。
Ⅰ.字段的定义
public class Person{
//共有字段,可以被外部访问
public string name;
//私有字段,只能Person内部访问
private int age;
}
Ⅱ.字段初始化
public class Person{
//初始值未“Bob”
public string name = "Bob";
//默认初始值为0
private int age;
}
Ⅲ.只读字段
- 使用const的时候需要在声明字段时初始化。
- 使用 readonly 关键字可以声明只读字段,可以在声明时或者构造函数中初始化。
- 只读字段只能在声明时或在类的构造函数中赋值,一旦赋值后就不能再修改。
Person p = new Person("ZJU");
//p.School = "THU";School只读不能修改
public class Person
{
public const string name = "Lisa";
// 只读字段,在声明时初始化
public readonly int Id = 12345;
// 只读字段,在构造函数中初始化
public readonly string School;
public Person(string school)
{
School = school;
}
}
Ⅳ.静态字段
使用 static 关键字可以声明静态字段。静态字段属于类本身,而不是类的实例,所有实例共享同一个静态字段的值。
Counter c1 = new Counter();
Counter c2 = new Counter();
//输出实例化的个数,直接通过类名进行访问
Console.WriteLine(Counter.instanceCount);
public class Counter
{
// 静态字段,用于记录创建的实例数量
public static int instanceCount = 0;
public Counter()
{
//每次创建新实例,计数器+1
instanceCount++;
}
}
Ⅴ.字段的访问控制
通过不同的访问修饰符(如 public、private、protected、internal 等)可以控制字段的访问级别,从而实现信息隐藏和封装。
2.属性
Ⅰ.属性基础概念
- 属性(Property)是一种用于封装类、结构体或接口中的字段的成员,它在外部提供了统一的访问方式,隐藏了内部字段的具体实现细节,增强了类的封装性和安全性。同时,属性还可以在数据访问时添加额外的逻辑,如数据验证、计算等。
Ⅱ.属性的声明
- 自动属性:编译器会自动生成一个私有字段来存储属性的值,开发者无需手动定义。优点:简洁。缺点:无法进行数据验证、计算等
- 传统属性:传统属性需要显式定义一个私有字段,并在属性的 get 和 set 访问器中编写逻辑来操作该字段。
Person p = new Person();
p.Name = "Lihua";
Console.WriteLine(p.Name);
public class Person
{
//声明私有字段
private string name;
//属性
public string Name
{
get { return name; }
set { name = value; }
}
//自动实现属性
public int Age { get; set; }
}
Ⅲ.只读/只写属性
- 只读属性:只包含 get 访问器的属性称为只读属性,它的值通常在对象创建时初始化,之后不能被修改。
class Circle
{
private readonly double radius;
public Circle(double radius)
{
this.radius = radius;
}
public double Area
{
get { return radius * radius * Math.PI; }
}
}
- 只写属性:只包含 set 访问器的属性称为只写属性,很少使用这种情况。
Ⅳ.属性访问修饰符
- get 和 set 访问器可以有不同的访问修饰符,比如public,private等。
Student s = new Student();
s.SetScore(99.99);//只能通过SetScore方法来给_score赋值
Console.WriteLine(s.Score);
public class Student
{
private double _score;
public double Score
{
get { return _score; }
private set { _score = value; }
}
public void SetScore(double myScore)
{
_score = myScore;
}
}
Ⅴ.静态属性
- 使用static关键字,静态属性属于类本身,直接通过类名来访问。
Calculator.Add(1, 1);
Calculator.Add(1, 2);
Console.WriteLine(Calculator.Count);
public class Calculator
{
private static int _count;
public static int Count
{
get { return _count; }
set { _count = value; }
}
public static int Add(int a, int b)
{
_count++;
return a + b;
}
}
3.索引器
索引器(Indexer)是一种特殊的属性,它允许对象像数组一样通过索引来访问其元素,提供了一种简洁且直观的方式来访问对象中的一组数据。
Ⅰ.基础语法
使用 this 关键字,并指定索引参数的类型和数量。
[访问修饰符] 返回类型 this[索引类型 参数名]
{
get
{
// 获取索引位置元素的逻辑
}
set
{
// 设置索引位置元素的逻辑
}
}
MyArray ma = new MyArray();
ma[0] = "abc";
Console.WriteLine(ma[0]);
public class MyArray
{
private string[] _arr = new string[10];
public string this[int index]
{
get
{
if(index < 0 || index > _arr.Length)
{
throw new IndexOutOfRangeException();
}
return _arr[index];
}
set
{
if (index < 0 || index > _arr.Length)
{
throw new IndexOutOfRangeException();
}
_arr[index] = value;
}
}
}
索引器的索引参数可以是除 ref 和 out 之外的任何类型,常见的有 int、string 等。
string 类型索引:使用字符串作为索引值来访问对象的元素。这种索引类型适用于需要通过名称或键来访问元素的场景,类似于字典。
MyArray ma = new MyArray();
ma["A"] = 1;
ma["B"] = 2;
Console.WriteLine(ma["A"]);
Console.WriteLine(ma["B"]);
public class MyArray
{
private Dictionary<string, int> data = new Dictionary<string, int>();
public int this[string index]
{
get { return data[index]; }
set { data[index] = value; }
}
}
Ⅱ.多维索引器
索引器也可以支持多个索引参数,从而实现多维数组的访问。
Matrix m = new Matrix();
m[1, 2] = 0;
m[1, 3] = 10;
Console.WriteLine($"{m[1,2]},{m[1,3]}");
public class Matrix
{
private int[,] _matrix = new int[3, 4];
public int this[int row,int col]
{
get { return _matrix[row,col]; }
set { _matrix[row,col] = value; }
}
}
Ⅲ.索引器重载
索引器重载是指在一个类中定义多个具有不同参数列表的索引器。
Matrix m = new Matrix();
// 使用第一个索引器设置和获取 _count 数组元素
m[5] = 10;
Console.WriteLine(m[5]);
// 使用第二个索引器设置和获取 _name 数组元素
m[1, true] = "ABC";
Console.WriteLine(m[1, true]);
// 使用第三个索引器设置和获取 _name 数组元素
m["1"] = "CCD";
Console.WriteLine(m["1"]);
public class Matrix
{
private int[] _count = new int[10];
private string[] _name = new string[10];
// 重载索引器:使用整数索引访问 _count 数组
public int this[int index]
{
get
{
if(index >= 0 || index < _count.Length)
{
return _count[index];
}
throw new IndexOutOfRangeException();
}
set
{
if (index >= 0 || index < _count.Length)
{
_count[index] = value;
}
else
{
throw new IndexOutOfRangeException();
}
}
}
// 重载索引器:使用整数索引访问 _name 数组
public string this[int index,bool isNameArray]
{
get
{
if (isNameArray)
{
if(index >= 0 || index < _count.Length)
{
return _name[index];
}
else
{
throw new IndexOutOfRangeException();
}
}
throw new ArgumentException("无效参数");
}
set
{
if (isNameArray)
{
if(index >= 0 || index < _count.Length)
{
_name[index] = value;
}
else
{
throw new IndexOutOfRangeException();
}
}
else
{
throw new ArgumentException("无效参数");
}
}
}
// 重载索引器:使用string索引访问 _name 数组
public string this[string index]
{
get
{
if(int.TryParse(index,out int _index) && _index >= 0|| _index < _name.Length)
{
return _name[_index];
}
throw new ArgumentException("无效的字符串索引或索引超出 _name 数组范围");
}
set
{
if (int.TryParse(index, out int _index) && _index >= 0 || _index < _name.Length)
{
_name[_index] = value;
}
else
{
throw new ArgumentException("无效的字符串索引或索引超出 _name 数组范围");
}
}
}
}