类
类的声明和实例化
class A{
}
// another file
F(){
A a = new A(); // 实例化类,new <类名>(实例化参数)
A aa;
aa = new A(); // 先声明后实例化同样可行
}
类的成员
字段和方法
class A {
private string Name;
protected int Seq;
internal int Abc;
public int Score;
public void Foo(int x) {
}
}
class B {
public static int Bef;
public static int Bar() {
}
}
F(){
A a = new A(); // A中成员和方法都是非静态的,所以先创建一个A的实例
System.Console.WriteLine(a.score)
System.Console.WriteLine(B.b); // B中成员和方法都是静态的,所以通过类调用
}
属性
class A {
private string _Name; // 当综合使用private字段和public属性时
public string Name {
// 用下划线加PascalCase为private字段命名,用PascalCase为public属性命名
get{
return _Name; }
set{
_Name = value; }
}
}
class B {
private string _Name;
public string Name{
get => _Name;
set => _Name = value; // 简化主体式表达方法
}
public int Seq {
get; set; } // 使用自动实现的属性方法
}
在对属性使用或赋值时进行操作
class A {
private string _Name;
public string Name {
get => _Name;
set {
if (value == null)
throw new ArgumentNullException(nameof(value));
else if (value == "")
throw new ArgumentException("Value can't be empty", nameof(value));
else
_Name = value;
} // 对属性赋值进行检查
}
public int Seq {
get;
private set; // 把属性的方法声明为private就可以覆盖属性的public,这样只有本类才能使用set
// 注意:set只能比get更私有,若如果set为public,get为private则出错
}
public string Info {
// 虚属性
get => $"{Seq} {Name}";
set {
string[] info = value.Split(new char[] {
' ' });
if (info.Length == 2 && int.TryParse(info[0], out int seq))
{
// not `out Seq` 属性不作out和ref的参数
Name = info[1];
Seq = seq;
}
else
throw new ArgumentException($"{value} is invalid");
}
}
public int Score {
get; // 只定义了get,则为只读属性
}
public bool pass {
get; set; } = false; // 初始化属性
}
用自动实现的属性代替public,protected字段
注意不要出现如下代码
class A {
public string Name {
get; // Error
set => Name = value; // 错误:死循环
}
}
关键字this
class A {
private string Name;
private int Seq;
public void SetA(string name, int seq)
{
this.Name = name;
this.Seq = seq;
// this作为对自身的引用
}
}
没有必要不使用this
构造函数和解构函数
class A {
public string Name {
get; set; }
public int Seq {
get; set; } = -1;
public int Score {
get; set; }
public bool Pass {
get; set; }
public A(string name, int seq) {
// 构造函数名和类名一样
Name = name;
Seq = seq;
}
public A(string name) => Name = name; // 重载构造函数,考虑为构造函数添加默认值而非简单重构
public A() :
this(string.Empty, -1) // 构造函数链,在C++中称为委托构造函数
{
Score = 59;
}
public void Deconstruct( // 解构函数,必须为void Deconstruct (out type typename) 形式
out string name,
out int seq,
out int score,
out bool pass
)
{
(name, seq, score, pass) = (Name, Seq, Score, Pass);
}
}
void Foo() {
A a = new A("Alice", 12); // 调用构造函数,我们给Seq的默认值-1会被覆盖
// new 获取空白内存,传递给构造函数进行实例化,再返回内存的引用
A aa = new A("Bob", 45) {
Score = 60, Pass = true