C# 面向对象 - 抽象类与接口

12.1 抽象类

定义抽象类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public abstract class Shape
{
// 抽象属性
public abstract double Area { get; }

// 抽象方法
public abstract double CalculatePerimeter();

// 普通方法
public void Display()
{
Console.WriteLine($"面积: {Area:F2}");
}
}

实现抽象类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Rectangle : Shape
{
public double Width { get; set; }
public double Height { get; set; }

public override double Area => Width * Height;

public override double CalculatePerimeter()
{
return 2 * (Width + Height);
}
}

public class Circle : Shape
{
public double Radius { get; set; }

public override double Area => Math.PI * Radius * Radius;

public override double CalculatePerimeter()
{
return 2 * Math.PI * Radius;
}
}

12.2 抽象类特点

  • 不能直接实例化
  • 可以包含抽象成员和普通成员
  • 派生类必须实现所有抽象成员
  • 用于定义相关类的共同基类
1
2
3
4
// Shape shape = new Shape();  // 错误:不能实例化抽象类

Shape rect = new Rectangle { Width = 5, Height = 3 };
Console.WriteLine(rect.Area); // 15

12.3 接口定义

基本接口

1
2
3
4
5
6
7
public interface IRepository<T>
{
void Add(T item);
void Remove(T item);
T GetById(int id);
IEnumerable<T> GetAll();
}

接口实现

1
2
3
4
5
6
7
8
9
10
11
12
public class ProductRepository : IRepository<Product>
{
private List<Product> _products = new();

public void Add(Product item) => _products.Add(item);

public void Remove(Product item) => _products.Remove(item);

public Product GetById(int id) => _products.FirstOrDefault(p => p.Id == id);

public IEnumerable<Product> GetAll() => _products;
}

12.4 接口特点

  • 只能包含方法、属性、事件、索引器签名
  • 所有成员默认 public,不能指定访问修饰符
  • 类可以实现多个接口
  • 接口可以继承接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public interface IDrawable
{
void Draw();
}

public interface IColorable
{
string Color { get; set; }
}

// 多接口实现
public class Circle : IDrawable, IColorable
{
public void Draw() => Console.WriteLine("绘制圆形");
public string Color { get; set; }
}

12.5 显式接口实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public interface IWorker
{
void Work();
}

public interface IManager
{
void Work();
}

public class TeamLead : IWorker, IManager
{
// 显式实现
void IWorker.Work()
{
Console.WriteLine("执行具体工作");
}

void IManager.Work()
{
Console.WriteLine("管理团队工作");
}

// 需要转换接口才能调用
public void DoWork()
{
((IWorker)this).Work();
((IManager)this).Work();
}
}

12.6 接口继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public interface IAnimal
{
void Eat();
}

public interface IFlyable
{
void Fly();
}

// 接口继承
public interface IBird : IAnimal, IFlyable
{
void LayEggs();
}

public class Eagle : IBird
{
public void Eat() => Console.WriteLine("鹰吃肉");
public void Fly() => Console.WriteLine("鹰飞翔");
public void LayEggs() => Console.WriteLine("鹰下蛋");
}

12.7 默认接口方法(C# 8+)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public interface ILogger
{
void Log(string message);

// 默认实现
void LogError(string message)
{
Log($"ERROR: {message}");
}

void LogWarning(string message)
{
Log($"WARNING: {message}");
}
}

public class ConsoleLogger : ILogger
{
public void Log(string message)
{
Console.WriteLine(message);
}
}

// 使用默认方法
ILogger logger = new ConsoleLogger();
logger.LogError("Something went wrong");

12.8 抽象类 vs 接口

特性 抽象类 接口
实例化 不能 不能
成员实现 可以有 C# 8+ 可以有默认实现
字段 可以有 不能有
构造函数 可以有 不能有
继承 单继承 多实现
访问修饰符 支持 默认 public
用途 “是什么” “能做什么”

选择建议

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 使用抽象类:相关类共享代码
abstract class Vehicle
{
public abstract void Start();
public void Stop() => Console.WriteLine("停止");
}

// 使用接口:定义能力
interface ISerializable
{
string Serialize();
}

interface IComparable<T>
{
int CompareTo(T other);
}

12.9 本章小结

  • 抽象类使用 abstract 关键字,不能实例化
  • 抽象成员必须在派生类中实现
  • 接口定义契约,类可实现多个接口
  • 显式接口实现解决命名冲突
  • 接口可以继承其他接口
  • C# 8+ 支持默认接口方法
  • 抽象类用于”是什么”,接口用于”能做什么”

练习题

  1. 创建抽象类 Employee,派生 ManagerDeveloper
  2. 定义 IPrintable 接口,实现打印功能
  3. 使用显式接口实现解决冲突
  4. 以下代码能否编译?
    1
    2
    interface ITest { void Method(); }
    class Test : ITest { private void Method() { } }
ByteFisher
分享编程技术 · 记录钓鱼乐趣
扫码关注
▸ 扫码关注 ◂
分享: