提问人:lomaxx 提问时间:8/15/2008 最后编辑:John Smithlomaxx 更新时间:11/9/2023 访问量:1383368
在 C 中调用基构造函数#
Calling the base constructor in C#
问:
如果我从基类继承,并希望将某些内容从继承类的构造函数传递到基类的构造函数,我该怎么做?
例如,如果我从 Exception 类继承,我想做这样的事情:
class MyExceptionClass : Exception
{
public MyExceptionClass(string message, string extraInfo)
{
//This is where it's all falling apart
base(message);
}
}
基本上,我想要的是能够将字符串消息传递给基 Exception 类。
答:
将构造函数修改为以下内容,以便它正确调用基类构造函数:
public class MyExceptionClass : Exception
{
public MyExceptionClass(string message, string extrainfo) : base(message)
{
//other stuff here
}
}
请注意,构造函数不是可以在方法中随时调用的东西。这就是您在构造函数正文中的调用中遇到错误的原因。
评论
public class MyExceptionClass : Exception
{
public MyExceptionClass(string message,
Exception innerException): base(message, innerException)
{
//other stuff here
}
}
可以将内部异常传递给其中一个构造函数。
请注意,可以在对基构造函数的调用中使用静态方法。
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;
}
}
评论
如果你需要调用基构造函数,但不是立即调用,因为你的新(派生的)类需要做一些数据操作,最好的解决方案是求助于工厂方法。您需要做的是将派生构造函数标记为私有,然后在类中创建一个静态方法,该方法将执行所有必要的操作,然后调用构造函数并返回对象。
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);
}
}
评论
确实,使用 (something) 调用基类构造函数,但在重载的情况下使用关键字base
this
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
}
// Hint used overload as often as needed do not write the same code 2 or more times
评论
the keyword 'base' is not valid in this context
来自框架设计指南和 FxCop 规则。
1. 自定义异常的名称应以 Exception 结尾
class MyException : Exception
2. 例外应该是公开的
public class MyException : Exception
- 公共无参数构造函数。
- 具有一个字符串参数的公共构造函数。
- 具有一个字符串和 Exception 的公共构造函数(因为它可以包装另一个 Exception)。
序列化构造函数在类型未密封时受保护,如果类型密封,则受私有保护。 基于 MSDN:
[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. } }
或
[Serializable()]
public sealed 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.
}
private MyException(SerializationInfo info,
StreamingContext context) : base(info, context)
{
// Implement type-specific serialization constructor logic.
}
}
[Serializable]
internal class MyException : Exception
{
public MyException() {}
public MyException(string message) : base(message) {}
public MyException(string message, Exception innerException) : base(message, innerException) {}
protected MyException(SerializationInfo info, StreamingContext context) : base(info, context) {}
}
您还可以使用构造函数中的参数进行条件检查,这允许一些灵活性。
public MyClass(object myObject=null): base(myObject ?? new myOtherObject())
{
}
或
public MyClass(object myObject=null): base(myObject==null ? new myOtherObject(): myObject)
{
}
评论
根据此处列出的其他一些答案,您可以将参数传递到基类构造函数中。建议在继承类的构造函数的开头调用基类构造函数。
public class MyException : Exception
{
public MyException(string message, string extraInfo) : base(message)
{
}
}
我注意到,在您的示例中,您从未使用过该参数,因此我假设您可能希望将字符串参数连接到异常的属性(似乎在接受的答案和问题中的代码中忽略了这一点)。extraInfo
extraInfo
Message
这只需调用基类构造函数,然后使用额外信息更新 Message 属性即可实现。
public class MyException: Exception
{
public MyException(string message, string extraInfo) : base($"{message} Extra info: {extraInfo}")
{
}
}
示例,使用要从中派生的此基类:
public abstract class BaseClass
{
protected BaseClass(int a, int b, int c)
{
}
}
要执行的非编译伪代码:
public class DerivedClass : BaseClass
{
private readonly object fatData;
public DerivedClass(int m)
{
var fd = new { A = 1 * m, B = 2 * m, C = 3 * m };
base(fd.A, fd.B, fd.C); // base-constructor call
this.fatData = fd;
}
}
2020 版(请参阅下文了解更严格的解决方案)
使用较新的 C# 功能,即 ,您可以摆脱公共静态工厂方法。out var
我只是(偶然地)发现在 base-“call” 中调用的方法的 var 参数流向构造函数主体。(也许这是一个 C# 怪癖,请参阅 C# 1.0 兼容解决方案的 2023 版本)
使用静态私有帮助程序方法,该方法在外部生成所有必需的基本参数(如果需要,还可以生成其他数据),它只是一个公共纯构造函数:
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 更新
您只需要一个额外的私有构造函数和一个附带的私有静态工厂方法,该方法使用与公共 ctor 相同的输入为新的私有构造函数准备数据:
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# 版本,C#10 记录结构只是为了简短,也可以与任何 C#1.0 类一起使用。
这个版本似乎稍长,但更容易阅读和理解。
评论
this
base