简体   繁体   English

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

[英]Calling the base constructor in C#

If I inherit from a base class and want to pass something from the constructor of the inherited class to the constructor of the base class, how do I do that?如果我从基类继承并想将继承类的构造函数中的某些内容传递给基类的构造函数,我该怎么做?

For example, if I inherit from the Exception class I want to do something like this:例如,如果我从 Exception 类继承,我想做这样的事情:

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

Basically what I want is to be able to pass the string message to the base Exception class.基本上我想要的是能够将字符串消息传递给基异常类。

Modify your constructor to the following so that it calls the base class constructor properly:将您的构造函数修改为以下内容,以便它正确调用基类构造函数:

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

Note that a constructor is not something that you can call anytime within a method.请注意,构造函数不是您可以在方法中随时调用的东西。 That's the reason you're getting errors in your call in the constructor body.这就是您在构造函数主体中的调用中遇到错误的原因。

Note that you can use static methods within the call to the base constructor.请注意,您可以在对基本构造函数的调用中使用静态方法。

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

If you need to call the base constructor but not right away because your new (derived) class needs to do some data manipulation, the best solution is to resort to factory method.如果您需要调用基本构造函数但不是立即调用,因为您的新(派生)类需要进行一些数据操作,最好的解决方案是诉诸工厂方法。 What you need to do is to mark private your derived constructor, then make a static method in your class that will do all the necessary stuff and later call the constructor and return the object.您需要做的是将派生构造函数标记为私有,然后在您的类中创建一个静态方法,该方法将完成所有必要的工作,然后调用构造函数并返回对象。

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

It is true use the base (something) to call the base class constructor, but in case of overloading use the this keyword确实使用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
public class MyExceptionClass : Exception
{
    public MyExceptionClass(string message,
      Exception innerException): base(message, innerException)
    {
        //other stuff here
    }
}

You can pass inner exception to one of the constructors.您可以将内部异常传递给构造函数之一。

From Framework Design Guidelines and FxCop rules.来自框架设计指南和 FxCop 规则。 :

1. Custom Exception should have a name that ends with Exception 1.自定义异常应该有一个以异常结尾的名字

    class MyException : Exception

2. Exception should be public 2.异常应该是公开的

    public class MyException : Exception

3. CA1032: Exception should implements standard constructors. 3. CA1032:异常应该实现标准构造函数。

  • A public parameterless constructor.公共无参数构造函数。
  • A public constructor with one string argument.带有一个字符串参数的公共构造函数。
  • A public constructor with one string and Exception (as it can wrap another Exception).具有一个字符串和异常的公共构造函数(因为它可以包装另一个异常)。
  • A serialization constructor protected if the type is not sealed and private if the type is sealed.如果类型不是密封的,则序列化构造函数受保护,如果类型是密封的,则为私有。 Based on MSDN :基于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. } }

or或者

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

You can also do a conditional check with parameters in the constructor, which allows some flexibility.您还可以对构造函数中的参数进行条件检查,这具有一定的灵活性。

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

or或者

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

As per some of the other answers listed here, you can pass parameters into the base class constructor.根据此处列出的其他一些答案,您可以将参数传递给基类构造函数。 It is advised to call your base class constructor at the beginning of the constructor for your inherited class.建议在继承类的构造函数的开头调用基类构造函数。

public class MyException : Exception
{
    public MyException(string message, string extraInfo) : base(message)
    {
    }
}

I note that in your example you never made use of the extraInfo parameter, so I assumed you might want to concatenate the extraInfo string parameter to the Message property of your exception (it seems that this is being ignored in the accepted answer and the code in your question).我注意到,在您的示例中,您从未使用过extraInfo参数,因此我假设您可能希望将extraInfo字符串参数连接到异常的Message属性(似乎在接受的答案和代码中忽略了这一点你的问题)。

This is simply achieved by invoking the base class constructor, and then updating the Message property with the extra info.这只需调用基类构造函数,然后使用额外信息更新 Message 属性即可实现。

public class MyException: Exception
{
    public MyException(string message, string extraInfo) : base($"{message} Extra info: {extraInfo}")
    {
    }
}
public class MyException : Exception
{
    public MyException() { }
    public MyException(string msg) : base(msg) { }
    public MyException(string msg, Exception inner) : base(msg, inner) { }
}
class Exception
{
     public Exception(string message)
     {
         [...]
     }
}

class MyExceptionClass : Exception
{
     public MyExceptionClass(string message, string extraInfo)
     : base(message)
     {
         [...]
     }
}

Using newer C# features, namely out var , you can get rid of the static factory-method.使用较新的 C# 功能,即out var ,您可以摆脱静态工厂方法。 I just found out (by accident) that out var parameter of methods called inse base-"call" flow to the constructor body.我刚刚(偶然)发现称为 inse base-"call" 的方法的 out var 参数流向构造函数主体。

Example, using this base class you want to derive from:例如,使用您要从中派生的这个基类:

public abstract class BaseClass
{
    protected BaseClass(int a, int b, int c)
    {
    }
}

The non-compiling pseudo code you want to execute:您要执行的非编译伪代码:

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

And the solution by using a static private helper method which produces all required base arguments (plus additional data if needed) and without using a static factory method, just plain constructor to the outside:解决方案是使用静态私有辅助方法,该方法生成所有必需的基本参数(如果需要,还可以添加其他数据),并且不使用静态工厂方法,只需向外部构造简单的构造函数:

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;
    }
}
public class Car
{
     public Car(string model)
     {
        Console.WriteLine(model);
     }
}

public class Mercedes : Car
{
     public Mercedes(string model): base(model)
     {

     }
}

Usage:用法:

Mercedes mercedes = new Mercedes("CLA Shooting Brake");

Output: CLA Shooting Brake输出:CLA 射击刹车

Add : base("string or something") after the constructor, not inside its body.添加: base("string or something")在构造函数之后,而不是在其主体内。

public class MyException : System.Exception {
    public MyException(string msg) : base(msg) {
        // code here
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM