4

So I was looking at the documentation to understand how to use an object initializer, be it for anonymous types or not. The only thing that I would like to find out is why(and if it matters) is there a difference in the example.

It goes like this: for a Cat

class Cat
{
    public int Age { get; set; }
    public string Name { get; set; }
}

I can see the first example like so:

Cat cat = new Cat { Age = 10, Name = "Fluffy" };

This makes sense. But then, you can find the following:

List<Cat> cats = new List<Cat>
{
    new Cat(){ Name = "Sylvester", Age=8 },
    new Cat(){ Name = "Whiskers", Age=2 }
};

Now my question is: (why) is there a difference between new Cat{...} and new Cat(){...} ? Why should we use(or not) the parentheses?

1
  • I wish such "optimizations" of a language should take a time to consider the balance between advantages -- spares you from adding () -- and disadvantages -- the confusion and all fuss it draws plus a new rule to remember that you can only use this syntactic candy when the class has a parameterless constructor. As a side note, in C++ it has a purpose: zero initialization vs indeterminate value. Commented Apr 17, 2021 at 10:12

2 Answers 2

6

If an object has a parameterless constructor, you can omit the parentheses. So both of these are valid

// Assuming cat has a constructor with no parameters
Cat cat = new Cat { Age = 10, Name = "Fluffy" };
Cat cat = new Cat() { Age = 10, Name = "Fluffy" };

The List<T> itself has an object initializer where you can provide any number of items, and they are automatically added to the collection.

List<Cat> cats = new List<Cat>()
{
    new Cat(){ Name = "Sylvester", Age=8 }, // Add sylvester to the List
    new Cat(){ Name = "Whiskers", Age=2 } // And Whiskers too
};

As mentioned above you can also remove the parentheses here aswell

List<Cat> cats = new List<Cat>
{
    new Cat { Name = "Sylvester", Age=8 }, // Add sylvester to the List
    new Cat { Name = "Whiskers", Age=2 } // And Whiskers too
};
Sign up to request clarification or add additional context in comments.

4 Comments

I think your reference to the parameterless constructor (name) was pretty important, since it's used to specify error messages in different libraries like EF
@Jamiec , it seems that this is the part I was missing: If an object has a no parameter constructor, you can omit the parentheses
@CamiloTerevinto, can you elaborate a bit on what you've just pointed?
@bgiuga A constructor that takes no parameters is called a parameterless constructor. It's important to know the name because there are libraries that refer explicitly to them when throwing error messages
6

These are just two acceptable equivalent syntax for instantiation of objects in C# with object initialization (you can't omit the parenthesis if you are just doing var cat = new Cat();).

  • since your class has no explicit constructor, a default parameter-less constructor is provided to the Cat class
  • new Cat {...} allows to instantiate and initialize properties of the Cat object as a shortcut for new Cat() {...}, calling the mentioned constructor.

The part about the constructor is important. If there is no implicit default constructor / explicit parameter-less constructor, then you cannot omit the parenthesis, and you'll have to provide parameters in them anyway :

public class Cat {
    public string Name;
    public int Age;

    public Cat(string s) { // since I provide a constructor with parameter here, no parameterless constructor exists
        Name = s; 
    } 
}

// ...
void TestCat() 
{

    // compilation error : 'Cat'' does not contain a constructor that takes 0 arguments
    //var badCat1 = new Cat { Name = "Felix", Age = 3} ;
    //var badCat2 = new Cat() { Name = "Felix", Age = 3} ;

    // works (but no way to remove parenthesis here, since there are parameters to pass to csontructor)
    var goodCat = new Cat("Felix") { Age = 3 } ;

    Console.WriteLine($"The cat {goodCat.Name} is {goodCat.Age} years old");
}

Special case : (which is used a lot for collections, list, dictionaries, etc...).

If a class T implements IEnumerable (i.e. has a IEnumerable GetEnumerator() public function), and implements an Add method, then the object initializer will use the Add method with the collection on enumeration.

Example from https://blog.mariusschulz.com/2014/06/26/fun-with-custom-c-collection-initializers

Creation of special class "Points" which acts like a "List" with the initialization.

Note that this also uses the existing parameter-less constructor !

public class Points : IEnumerable<Point3D>
{
    private readonly List<Point3D> _points;

    public Points()
    {
        _points = new List<Point3D>();
    }

    public void Add(double x, double y, double z)
    {
        _points.Add(new Point3D(x, y, z));
    }

    public IEnumerator<Point3D> GetEnumerator()
    {
        return _points.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

Used like that :

var cube = new Points
{
    { -1, -1, -1 },
    { -1, -1,  1 },
    { -1,  1, -1 },
    { -1,  1,  1 },
    {  1, -1, -1 },
    {  1, -1,  1 },
    {  1,  1, -1 },
    {  1,  1,  1 }
};

4 Comments

For any downvoter, please explain how this is wrong, so I can improve and/or delete my answer.
You might want to go a bit more into detail regarding the questions at the bottom: "(why) is there a difference between new Cat{...} and new Cat(){...} ? Why should we use(or not) the parentheses?"
@ManfredRadlwimmer thanks for your input. I added more details, and trying not to be too redundant with the other accepted answer.
Upvoted, for mentioning what's behind the scenes for the collections initializers

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.