Home > Software engineering >  C# - When i try to create constructor, i get CS7036 error
C# - When i try to create constructor, i get CS7036 error

Time:10-16

Firstly, sorry for my English. I hope i can explain my problem.

I have class like this

public class CarCommandExecutorBase
{
    protected readonly ICarCommand CarCommand;
    public CarCommandExecutorBase(ICarCommand carCommand)
    {
        CarCommand = carCommand;
    }
}

Also i have class like this

public class CarStringCommandExecutor : CarCommandExecutorBase, IStringCommand
{
    private Car _Car;
    public CarStringCommandExecutor(Car car)
    {
        _Car = car;
        // this Constructor gives me an error.
    }
    public void ExecuteCommand(string commandObject)
    {
        if (string.IsNullOrEmpty(commandObject))
            throw new Exception("Komutlarda hata var.");

        char[] commands = commandObject.ToCharArray();

        for (int i = 0; i < commands.Length; i  )
        {
            switch (commands[i])
            {
                case 'L':
                    break;
                case 'R':
                    break;
                case 'M':
                    break;
                default:
                    throw new Exception("Komutlarda hata var.");
            }
        }
    }
}

Error message: error

What's the reason and how can i fix it? Thanks.

CodePudding user response:

One of the things that isn't immediately apparent, thanks to "compiler magic", about a C# class is that every class has a constructor

It needs to be this way because it's a rule that object construction happens in a tree; you construct some class Z which inherits from Y which inherits from X which inherits from object, and Z's cosntructor invokes Y's invokes X's invokes object's, then they finish, in order of object, X, Y, Z and you have your nicely constructed thing - every constructor on the way up the tree had its chance to do its init and ready the object for use (the part of it that each constructor was responsible for)

Even classes that don't seem to have constructors, have constructors:

class X { 

}

If you don't provide a constructor, C# provides one for you. You never see it in your source code; just imagine that in between reading the file and compiling it, the compiler inserts it for you. It takes no parameters, has no code, and does nothing other than call its base:

class X { 
  X():base() { } //C# invisibly writes this for you
}

If you provide a constructor but don't write the base... bit, C# puts base() in for you behind the scenes (and it always calls the no-argument base()) but critically it doesn't provide an empty constructor if you provided one already

This means if you have a class like:

class X{
  X(string message){
    ...
  }
}

Your class X has a constructor, so C# won't provide the empty one, so now anything that tries to construct your class must provide a string message:

X x = new X("hello");

If you now inherit from X, you might do one of 3 things (with Y):

class Y:X{

}
  1. You don't add a constructor, C# adds one, but it just dumbly calls base(), which doesn't work because there is no constructor in X that takes no args:

     class Y:X{ 
       Y():base() { }
     }
    
  2. You add a constructor but leave off the base bit. C# adds it, again just literally as base() - this also doesn't work for the same reason

    class Y:X{ 
       Y(int myArg)        //c# adds base() in here for you
       { 
         ...
       }
     }
    
  3. You add a constructor that includes a call to base and because you know your base class only has a constructor with a string arg, you pass one:

    class Y:X{ 
      Y(int myArg) : base("hello")
      { 
        ...
      }
    }
    

So you're in scenario 2, and you either need to:

  • Add a no-arg constructor to the base class so that c#'s auto-inserted stuff works or,
  • Add a call to base(...) with a suitable argument, to stop C# from putting a base() in

I've left out access modifiers from code in this answer for clarity of demonstrating the essential point. Whether a constructor is accessible or not can also have a bearing on all this, but I deemed it out of scope

CodePudding user response:

Since the only constructor in CarCommandExecutorBase is defined like this

public CarCommandExecutorBase(ICarCommand carCommand)
{
    CarCommand = carCommand;
}

you have to pass an ICarCommand when creating an instance of CarCommandExecutorBase.

You have to provide an ICarCommand through the constructor of CarStringCommandExecutor, because when instantiating a derived type the base constructor(s) also get called.

See this answer for more detailed information about this: https://stackoverflow.com/a/1882778/8450550

You could do something like this to solve this error:

public class CarStringCommandExecutor : CarCommandExecutorBase, IStringCommand
{
    ...

    public CarStringCommandExecutor(Car car, ICarCommand carCommand)
        : base(carCommand) // base() points to the constructor of the base class
    {
        ...
    }

or maybe this

public class CarStringCommandExecutor : CarCommandExecutorBase, IStringCommand
{
    ...

    public CarStringCommandExecutor(Car car)
        : base(null) // passing null but be aware of NullReferenceExceptions
    {
        ...
    }

or you add another constructor to CarCommandExecutorBase which expects no arguments:

public class CarCommandExecutorBase
{
    protected readonly ICarCommand CarCommand;
    public CarCommandExecutorBase(ICarCommand carCommand)
    {
        CarCommand = carCommand;
    }

    // mark this constructor as protected, so only deriving types can call it
    protected CarCommandExecutorBase()
    {

    }
}

Which solution works best in your case is up to you.

  • Related