在C#中调用基类构造函数

在C#中调用基类构造函数

技术背景

在C#编程中,当创建一个派生类时,常常需要调用基类的构造函数来初始化基类的成员。正确调用基类构造函数是确保类继承体系正常工作的关键。同时,在自定义异常类时,遵循一定的规范可以使代码更具可读性和可维护性。

实现步骤

直接调用基类构造函数

可以在派生类的构造函数中使用 base 关键字直接调用基类的构造函数。示例代码如下:

1
2
3
4
5
6
7
public class MyExceptionClass : Exception
{
public MyExceptionClass(string message, string extrainfo) : base(message)
{
//other stuff here
}
}

使用静态方法调用基类构造函数

可以在调用基类构造函数时使用静态方法。示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
class MyExceptionClass : Exception
{
public MyExceptionClass(string message, string extraInfo) :
base(ModifyMessage(message, extraInfo))
{
}

private static string ModifyMessage(string message, string extraInfo)
{
Trace.WriteLine("message was " + message);
return message.ToLowerInvariant() + Environment.NewLine + extraInfo;
}
}

使用工厂方法调用基类构造函数

当派生类需要进行一些数据处理后再调用基类构造函数时,可以使用工厂方法。示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class MyClass : BaseClass
{
private MyClass(string someString) : base(someString)
{
//your code goes in here
}

public static MyClass FactoryMethod(string someString)
{
//whatever you want to do with your string before passing it in
return new MyClass(someString);
}
}

重载构造函数调用

在构造函数重载时,可以使用 this 关键字调用同一个类的其他构造函数。示例代码如下:

1
2
3
4
5
public ClassName() : this(par1,par2)
{
// do not call the constructor it is called in the this.
// the base key- word is used to call a inherited constructor
}

条件检查调用基类构造函数

可以在构造函数中进行条件检查,然后根据条件调用基类构造函数。示例代码如下:

1
2
3
4
5
6
7
8
public MyClass(object myObject=null): base(myObject ?? new myOtherObject())
{
}

// 或者
public MyClass(object myObject=null): base(myObject==null ? new myOtherObject(): myObject)
{
}

自定义异常类的构造函数规范

自定义异常类需要遵循一定的规范,包括类名以 Exception 结尾、类为公共类以及实现标准构造函数。示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[Serializable()]
public class MyException : Exception
{
public MyException()
{
// Add any type-specific logic, and supply the default message.
}

public MyException(string message): base(message)
{
// Add any type-specific logic.
}
public MyException(string message, Exception innerException):
base (message, innerException)
{
// Add any type-specific logic for inner exceptions.
}
protected MyException(SerializationInfo info,
StreamingContext context) : base(info, context)
{
// Implement type-specific serialization constructor logic.
}
}

2020版本的实现

使用 out var 特性可以摆脱公共静态工厂方法。示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class DerivedClass : BaseClass
{
private readonly object fatData;

public DerivedClass(int m)
: base(PrepareBaseParameters(m, out var b, out var c, out var fatData), b, c)
{
this.fatData = fatData;
Console.WriteLine(new { b, c, fatData }.ToString());
}

private static int PrepareBaseParameters(int m, out int b, out int c, out object fatData)
{
var fd = new { A = 1 * m, B = 2 * m, C = 3 * m };
(b, c, fatData) = (fd.B, fd.C, fd); // Tuples not required but nice to use
return fd.A;
}
}

2023版本的实现

使用额外的私有构造函数和伴随的私有静态工厂方法。示例代码如下:

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
public class DerivedClass : BaseClass
{
private readonly FatData fatData;

public DerivedClass(int m)
: this(PrepareBaseParameters(m))
{
Console.WriteLine(this.fatData.ToString());
}

private DerivedClass(FatData fd)
: base(fd.A, fd.B, fd.C)
{
this.fatData = fd;
}

private static FatData PrepareBaseParameters(int m)
{
// might be any (non-async) code which e.x. calls factory methods
var fd = new FatData(A: 1 * m, B: 2 * m, C: 3 * m);
return fd;
}

private readonly record struct FatData(int A, int B, int C);
}

最佳实践

  • 遵循自定义异常类的命名和构造函数规范,提高代码的可读性和可维护性。
  • 尽量在派生类构造函数的开始处调用基类构造函数,确保基类成员正确初始化。
  • 当需要进行数据处理后再调用基类构造函数时,考虑使用工厂方法或额外的私有构造函数。

常见问题

  • 构造函数调用错误:构造函数不能在方法内部随时调用,否则会产生错误。
  • 参数使用问题:在调用基类构造函数时,需要确保传递的参数类型和数量与基类构造函数的定义一致。

在C#中调用基类构造函数
https://119291.xyz/posts/calling-the-base-constructor-in-csharp/
作者
ww
发布于
2025年5月26日
许可协议