ChatGPT解决这个技术问题 Extra ChatGPT

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

如果我从基类继承并想将继承类的构造函数中的某些内容传递给基类的构造函数,我该怎么做?

例如,如果我从 Exception 类继承,我想做这样的事情:

class MyExceptionClass : Exception
{
     public MyExceptionClass(string message, string extraInfo)
     {
         //This is where it's all falling apart
         base(message);
     }
}

基本上我想要的是能够将字符串消息传递给基异常类。

还值得注意的是,您可以通过将 this 替换为 base 来链接当前类中的构造函数。
与其说“一切都崩溃了”,不如只发布你遇到的错误更有帮助
尝试: public class MyExceptionClass : Exception { public MyExceptionClass(string message, string extrainfo) : base(message) { //这里的其他东西 } }
@Quibblesome 我找不到用 .this 代替 .base 的示例。我可能措辞不正确,但你有什么例子吗?我的问题是,如果您确实替换了,您是否不再需要 :base 在参数中并且可以只在构造函数中使用 .base ?

J
Jon Limjap

将您的构造函数修改为以下内容,以便它正确调用基类构造函数:

public class MyExceptionClass : Exception
{
    public MyExceptionClass(string message, string extrainfo) : base(message)
    {
        //other stuff here
    }
}

请注意,构造函数不是您可以在方法中随时调用的东西。这就是您在构造函数主体中的调用中遇到错误的原因。


我想你可能错过了重点。问题在于在被覆盖的构造函数中途调用基本构造函数。也许基本构造函数的数据类型不一样,或者您想在将其传递到链中之前进行一些数据成型。你将如何完成这样的壮举?
如果您需要在覆盖中间调用基构造函数,则将其提取到基类上您可以显式调用的实际方法中。基本构造函数的假设是它们对于安全地创建对象是绝对必要的,因此总是首先调用基。
它只是一种你可以随时调用的方法,IL 方面。 C# 恰好在此之上施加了额外的限制。
值得注意的是,base 构造函数在访问方法块之前调用msdn.microsoft.com/en-us/library/ms173115.aspx
如果您需要在构造函数的中途调用基类构造函数,这不是一个好的设计。构造函数的想法是它完成完成任务所需的所有工作。这样做的效果是,当您的派生构造函数启动时,基类已经完全初始化,派生类可以自由调用任何基类函数。如果你的设计是这样的,你想在你的构造函数中做一些事情,那么显然这不是初始化基类,因此不应该在基类的构造函数中,而是在一个单独的、可能受保护的函数中
A
Abhishek

请注意,您可以在对基本构造函数的调用中使用静态方法。

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;
     }
}

Exception 类被如此锁定,以至于我确实发现自己这样做了几次,但也请注意,如果你可以避免它,这不是你应该做的事情。
@kdbanman 那只是输出一条调试消息。没有相关的功能用途。
很好的答案。 Accepted answer 不允许我进行处理; followup comment on a workaround 假设我有权更改基类;我不。 A factory answer 假设我可以控制类的实例化方式;我不能。只有您的回答才能让我在将某些内容传递给基础之前对其进行修改。
只要中间功能在道德上是无国籍的,这绝对没有什么害处。日志记录不是一个好的用例,IMO,但规范化大小写或添加额外的似乎很好。
如果您处于上述情况。您可以将类构建为基类的包装器,而不是继承,作为替代解决方案。
a
aalimian

如果您需要调用基本构造函数但不是立即调用,因为您的新(派生)类需要进行一些数据操作,最好的解决方案是诉诸工厂方法。您需要做的是将派生构造函数标记为私有,然后在您的类中创建一个静态方法,该方法将完成所有必要的工作,然后调用构造函数并返回对象。

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);
    }
}

这可能会违反 SOLID 原则 (SRP),因为创建类的责任与该类应该负责的任何其他责任一起封装。可以使用抽象工厂,但可能会给简单代码增加不必要的复杂性。当然,如果您知道权衡和它将给您的架构带来的损失(以及如何解决您的设计决策可能出现的任何未来问题),那么违反 SOLID 是可以的。
s
shA.t

确实使用 base (something) 来调用基类构造函数,但在重载的情况下使用 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

我明白你想解释什么,你是对的。如果您在一个类中有两个构造函数,则可以使用“this”关键字从另一个中引用一个,类似于调用继承的构造函数时使用“base”的方式。但是,这不是 OP 要求的,所以这不是添加这个的地方。
S
SnowBEE
public class MyExceptionClass : Exception
{
    public MyExceptionClass(string message,
      Exception innerException): base(message, innerException)
    {
        //other stuff here
    }
}

您可以将内部异常传递给构造函数之一。


F
Fab

来自 Framework Design Guidelines 和 FxCop 规则。

1.自定义异常应该有一个以异常结尾的名字

    class MyException : Exception

2.异常应该是公开的

    public class MyException : Exception

<强> 3。 CA1032: Exception should implements standard constructors.

公共无参数构造函数。

带有一个字符串参数的公共构造函数。

具有一个字符串和异常的公共构造函数(因为它可以包装另一个异常)。

如果类型不是密封的,则序列化构造函数受保护,如果类型是密封的,则为私有。基于 MSDN: [Serializable()] public 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) { // 实现特定类型的序列化构造函数逻辑。 } }

或者

    [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.
      }
    }  

d
dynamiclynk

您还可以对构造函数中的参数进行条件检查,这具有一定的灵活性。

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

或者

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

是否有条件使用 2 个不同的基本构造函数?我的意思是其中一个有 2 个参数,另一个有 3 个参数?
@DavidCon 确保您可以在基类中创建多个具有不同签名\参数的构造函数,像上面一样使用它们。
我不能打电话给不同的基地建设者。我需要一些这样的想法: public MyClass(object myObject=null): base(myObject==null ? invokeConstructorBaseA: invokeConstructorBaseB){} 此外,ConstructorBaseA 有 2 个参数, ConstructorBaseB 有 3 个参数。有什么理由调用它们吗?
C
CShark

根据此处列出的其他一些答案,您可以将参数传递给基类构造函数。建议在继承类的构造函数的开头调用基类构造函数。

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}")
    {
    }
}

D
Donat Sasin
public class MyException : Exception
{
    public MyException() { }
    public MyException(string msg) : base(msg) { }
    public MyException(string msg, Exception inner) : base(msg, inner) { }
}

这是最好的答案,因为它也包含构造函数重载。
s
springy76

使用较新的 C# 功能,即 out var,您可以摆脱静态工厂方法。我刚刚(偶然)发现称为 inse base-"call" 的方法的 out var 参数流向构造函数主体。

例如,使用您要从中派生的这个基类:

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;
    }
}

解决方案是使用静态私有辅助方法,该方法生成所有必需的基本参数(如果需要,还可以添加其他数据),并且不使用静态工厂方法,只需向外部构造简单的构造函数:

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;
    }
}