3

I have a simple question about constructors in C#. Will these two code snippets behave the same way?

Code snippet #1:

public class foo
{
    public foo(string a = null, string b = null)
    {
      // do testing on parameters
    }
}

Code snippet #2:

public class foo
{
    public foo()
    {
    }

    public foo(string a)
    {
    }

    public foo(string a, string b)
    {
    }
}

EDIT: And if I add this to the code snippet #1? It may look a really bad idea, but I'm working on refactoring a legacy code, so I'm afraid if I do sth that will cause damage to other piece of that uses that class.

public class foo
{
    public foo(string a = null, string b = null)
    {
       if (a == null && b == null)
            {
                // do sth
            }else if (a != null && b == null)
            {
                // do sth
            }
            if (a != null && b != null)
            {
                // do sth
            }
            else
            {

            }
    }
}
  • 6
    try it yourself and see?? – Steve Apr 18 '18 at 16:41
  • Possible duplicate of [Can I give a default value to parameters or optional parameters in C# functions?](https://stackoverflow.com/questions/3914858/can-i-give-a-default-value-to-parameters-or-optional-parameters-in-c-sharp-funct) – Daniel A. Thompson Apr 18 '18 at 16:42
  • 2
    One thing that you may want to ask yourself as well, what happens if you only want to pass in the value for b in your constructor? – Sudsy1002 Apr 18 '18 at 16:42
  • Do they behave the same? Well, depends on what values yo upass in to them and what the content of the constructors are... – DavidG Apr 18 '18 at 16:44
  • 5
    If you have multiple constructors, you should make it a habit to use Construcor Chaining (https://stackoverflow.com/questions/1814953/c-sharp-constructor-chaining-how-to-do-it). Right now you would have to write the same code over and over again. However with chaining you chain from the Consturctor with the least parametrs to the one with the most, having the real code only in the final one. – Christopher Apr 18 '18 at 16:45
  • 2
    Yes neither one compiles. – P.Brian.Mackey Apr 18 '18 at 16:46
  • 1
    `Class` is not a keyword =) – Jcl Apr 18 '18 at 16:54

3 Answers3

9

The answer is no, the two are not going to behave the same.

The first snippet does not let your constructor decide if it has been called with a default parameter for a and/or b, or the caller has intentionally passed null. In other words, passing nulls intentionally becomes allowed, because you cannot implement a meaningful null check.

Another aspect in which these two code snippets would definitely differ - using constructors through a reflection:

  • The first snippet would provide one constructor. Reflection callers would need to deal with passing two parameters to it, or allowing optional parameters with binding flags (look at the demo provided by Jcl).
  • The second snippet would provide three separate constructors. Reflection callers would need to pick the one they wish to use.
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • Having a parameterless constructor may also be precondition to being usable - f.e. when dealing with wpf/xaml. – Patrick Artner Apr 18 '18 at 16:48
  • While the answer is correct, you *can* use reflection with optional parameters (with the correct binding flags). I've made a simple example: https://dotnetfiddle.net/sdKtSd – Jcl Apr 18 '18 at 16:52
  • @RufusL I mean checking for `null` becomes useless, because you don't know if a caller passed you a `null` (which is an error) or the caller didn't include the argument and you've got the default (which is not an error). – Sergey Kalinichenko Apr 18 '18 at 17:05
  • I understood it that way, but yes, the redaction could be better... like: "you can't check if the caller intentionally passed null or it was just not passed" or something, instead of "the inability to check for null" ;-) – Jcl Apr 18 '18 at 17:07
  • 1
    @Jcl Thank you very much for the comment. I edited to make this a separate point, and referenced your demo in the answer. – Sergey Kalinichenko Apr 18 '18 at 17:12
  • 1
    @AymenBenTanfous As long as your “do something“ doesn’t include throwing an exception, you should be fine. Also make sure that the class that you are modifying is not instantiated through reflection. – Sergey Kalinichenko Apr 19 '18 at 22:51
2

No. Try using named arguments. The overload version will not compile. Because a hasn't been given a value in the latter case.

var test = new foo1(b: "nope");
var test2 = new foo2(b: "nope");//CS7036 : There is no argument given that corresponds to the required formal parameter of
P.Brian.Mackey
  • 43,228
  • 68
  • 238
  • 348
1

if your are looking for a way to create an object with optional parameters just create inside your class a static factory method with optional or named parameter:

public class Foo
{
    public Foo(string a, string b, string c) { }

    public static Foo createInstance(string a = null, string b = null, string c = null) => new Foo(a, b, c);
}
Oliamster
  • 486
  • 5
  • 10