1

I'd like to start off with that I'm new to C# so accessors and Object Initializers are a completely new concept to me. That said, I think I have an okay handle on them except the following example is really confusing me:

using System;
using System.Collections.ObjectModel;

class How {
    public ObservableCollection<int> Coll {
        get { return coll_; }
        set {
            Console.WriteLine("Setter for Coll Called!");
            coll_.Clear();
            foreach (int i in value)
                coll_.Add(i);
        }
    }

    public string Field {
        get { return field_; }
        set {
            Console.WriteLine("Setter for field called");
            field_ = value;
        }
    }

    // To confirm the internal coll_ is actually set
    public void Test() {
        foreach(int i in coll_)
            Console.Write(i + " ");
    }

    public How() {
        coll_ = new ObservableCollection<int>();
        field_ = "";
    }

    private ObservableCollection<int> coll_;
    private string field_;
}

public class Test {
    public static void Main() {
        var how = new How {
            Coll = { 1, 2, 3, 4, 5 },
            Field = "Test Field",
        };

        Console.Write("Coll: ");
        foreach (int i in how.Coll)
            Console.Write(i + " ");
        Console.WriteLine();

        Console.WriteLine("Field: " + how.Field);


        Console.Write("Internal coll_: ");
        how.Test();
        Console.WriteLine();
    }
}

The output of the above code is (see live example here):

Setter for field called
Coll: 1 2 3 4 5 
Field: Test Field
Internal coll_: 1 2 3 4 5 

Field operates exactly as I'd expect it to, but Coll confuses me. The setter to Coll is never called, which to me implies that Collection Initializers don't mix will with Properties (or at least non Auto-Properties). However, if that's the case, I would have expected a compile-time error.

Regardless of that part of the behavior, what confuses me even further is that the internal value of coll_ is somehow set to the initializer value.

I'm interested in knowing a) why Coll's set is not called, and also how C# is able to set the value of coll_. Is the use of that identifier in the get and set accessors for Coll enough for C# to identify coll_ as the internal storage; or maybe since it's set because it's the only member of the corresponding type?

  • This line calls the Coll setter _Coll = { 1, 2, 3, 4, 5 },_ – Steve Jan 14 '17 at 11:44
  • @Steve I also thought so but it doesn't. Hold on, updating the question with a live example. – define cindy const Jan 14 '17 at 11:45
  • @Steve Added [this](http://ideone.com/rcYE1Y) live example to the question. – define cindy const Jan 14 '17 at 11:48
  • 2
    Collection initializers are translated into `Add` calls. Normally you'd see `new List { 1, 2, 3 }` in examples, but that consists of two parts: the `new` part and the collection initializer. Here, you only have the collection initializer - the `new`ing has already been done in `How`'s constructor. You should be seeing call(s?) to `Coll`'s getter instead. – Pieter Witvoet Jan 14 '17 at 12:03
  • @PieterWitvoet I had no idea it translated to repeated Add calls! That makes so much sense. Thank you for the help! :) – define cindy const Jan 14 '17 at 12:04
  • @definecindyconst, I saw your issue is resolved in a comment but I still posted an answer just in case because 1. it is good then Question has a clear Answer 2. I like collection initializers and I had some details to add :) – ASh Jun 20 '17 at 15:59

1 Answers1

1
var how = new How 
          {
              Coll = { 1, 2, 3, 4, 5 },
              Field = "Test Field",
          };

this is a object initialization syntax for How class.

Coll = { 1, 2, 3, 4, 5 } is a form of collection-itializer syntax meant for collection properties which don't have public setter (but works equally well with those which have setter). This form requieres for Coll to be instantiated (be not null): try to comment coll_ = new ObservableCollection<int>(); line in constructor and the program will crash with NullReferenceException.

Coll = { 1, 2, 3, 4, 5 } is translated in repeated Coll.Add calls:

Coll.Add(1);
Coll.Add(2);
Coll.Add(3);
Coll.Add(4);
Coll.Add(5);

to confirm it add event handler in How constructor:

public How() 
{
    coll_ = new ObservableCollection<int>();

    coll_.CollectionChanged += (o,e) => 
    { Console.WriteLine("New items: {0}", String.Join (",", e.NewItems.OfType<int>())); };

    field_ = "";
}

Collection initializers are described in §7.6.10.3 of C# Language Specification

Graham
  • 7,431
  • 18
  • 59
  • 84
ASh
  • 34,632
  • 9
  • 60
  • 82