Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How Does This List Assignment Work?

Tags:

c#

xamarin

I have seen this code example and it looks like it assigns an array initializer to a List. I thought it would not work but somehow it compiles. Is {} not an array initializer? Children is of type IList. How does it work without the "new List" before the curly braces?

        var nameLayout = new StackLayout()
        {
            HorizontalOptions = LayoutOptions.StartAndExpand,
            Orientation = StackOrientation.Vertical,
            Children = { nameLabel, twitterLabel }
        };

Edit: When I tried Children = new List<View>{ nameLabel, twitterLabel }, the compiler gives this warning: "Property or indexer Layout.Children cannot be assigned to, it is read-only."

The code fragment is from Xamarin by the way: https://developer.xamarin.com/guides/xamarin-forms/getting-started/introduction-to-xamarin-forms/

like image 952
John L. Avatar asked Sep 01 '16 15:09

John L.


People also ask

How do I assign multiple people to a list in Microsoft?

These are answers to your questions. 1) You can assign multiple people in task list, for that you do following. Go to List settings(Tasks)-->Click on Assigned To column, then Under Allow Multiple selections, select Yes radio button.

How do I accept assigned tasks in Outlook?

When colleagues create and assign you a task in Outlook, you receive a task assignment request. You can let the sender know whether you accept or decline the request. In the Reading Pane, click Accept or Decline. If the Reading Pane isn't turned on, open the task request and click Accept or Decline.

What is assignments and how does it work?

Assignments is an add-on application for learning management systems (LMSs) to help you distribute, analyze, and grade student work with Google Workspace for Education. Assignments makes Google Docs and Google Drive compatible with your LMS for file submissions.

What are the examples of assignment operator in Java Script?

Following are the examples of assignment operator in java script are given below: 1. Addition with Assignment Operator Example <p>JavaScript assignment operator is assigning a value to left hand side operand after the executing the right hand side operand operation.

What is assignments in Google Classroom?

How Assignments works Assignments is an add-on application for learning management systems (LMSs) to help you distribute, analyze, and grade student work with Google Workspace for Education. Assignments makes Google Docs and Google Drive compatible with your LMS for file submissions.

How to write a good assignment answer?

You need to be strictly formal and sound like an intellect in your assignment answer. Check for use of such slangs, the local language, local abbreviation and others in your assignment. If you are writing an inaugural speech in your assignment, you will not greet the audience with the opening line Wassup nigg*s.


2 Answers

That's a special case of a collection initializer.

In C#, the array initializer curly braces have been generalized to work with any collection class constructor.

Any class supports those if it implements System.Collections.IEnumerable and has one or more Add() methods. Eric Lippert has a good post about this type of "pattern matching" in C#: What the compiler is doing here is what they call "duck typing", rather than conventional strongly typed OOP where the capabilities of a class are recognized based on inheritance and interface implementation. C# does this in a few places. There's a lot of stuff in that article I hadn't known.

public class Foo : List<String>
{
    public void Add(int n)
    {
        base.Add(n.ToString());
    }
    public void Add(DateTime dt, double x)
    {
        base.Add($"{dt.ToShortDateString()} {x}");
    }
}

And then this compiles:

var f = new Foo { 0, 1, 2, "Zanzibar", { DateTime.Now, 3.7 } };

That's syntactic sugar for this:

var f = new Foo();

f.Add(0);
f.Add(1);
f.Add(2)
f.Add("Zanzibar");
f.Add(DateTime.Now, 3.7);

You can play some pretty weird games with these. I don't know if it's a good idea to go all out (actually I do know -- it isn't), but you can. I wrote a command-line parser class where you can define the options via a collection initializer. It's got over a dozen overloads of Add with varying parameter lists, many of them generic. Anything the compiler can infer is fair game.

Again, you can push this beyond diminishing returns to the point of feature abuse.

What you're seeing is an extension of the same initializer syntax, where it lets you do a collection initializer for a non-assignable member that the class itself already created:

public class Bar
{
    public Foo Foo { get; } = new Foo();
}

And now...

var b = new Bar { Foo = { 0, "Beringia" } };

{ 0, "Beringia" } is a collection initializer for the Foo instance that Bar created for itself; it's syntactic sugar for this:

var b = new Bar();

b.Foo.Add(0);
b.Foo.Add("Beringia");

The compiler's willingness to resolve overloads of Foo.Add() in the syntactic-sugar initializer usage makes sense when you look at it that way. I think it's great to be able to do that, but I'm not 100% comfortable with the syntax they chose. If you found the assignment operator to be a red herring, others will too.

But I'm not the Syntax Arbiter, and that's probably best for all concerned.

Finally, this also works with object initializers:

public class Baz
{
    public String Name { get; set; }
}

public class Bar
{
    public Foo Foo { get; } = new Foo { 1000 };
    public Baz Baz { get; } = new Baz { Name = "Initial name" };
}

So...

var b = new Bar { Foo = { 0, "Beringia" }, Baz = { Name = "Arbitrary" } };

Which actually turns into...

var b = new Bar();

b.Foo.Add(0);
b.Foo.Add("Beringia");
b.Baz.Name = "Arbitrary";

We can't initialize Bar.Baz because it's got no setter, but we can initialize its properties just as we can initialize the items in Foo. And that's true even if they've already been initialized by a different object initializer attached to the actual constructor.

Collection initializers, as you'd expect, are cumulative: Bar.Foo will have three items: { "1000", "0", "Beringia" }.

When you think of the curly braces as shorthand for a column of assignment statements or Add() overload calls, it all snaps into focus.

But I agree that the equals sign is jarring in cases where the lvalue is not actually being assigned to.

Bonus

Here's another pattern matching feature I learned about from that Eric Lippert article:

public static class HoldMyBeerAndWatchThis
{
    public static IEnumerable<int> Select(Func<String, String> f)
    {
        yield return f("foo").Length;
    }
}

Therefore...

var x = from s in HoldMyBeerAndWatchThis select s;

All you need for select to work is that the thing you're selecting from has to have a method named Select that returns something that quacks like IEnumerable as outlined in @EricLippert's remarks on foreach in the linked article (thanks Eric!), and takes a Func<T,T> parameter.

like image 129
15ee8f99-57ff-4f92-890c-b56153 Avatar answered Oct 12 '22 00:10

15ee8f99-57ff-4f92-890c-b56153


There seems to be some confusion in the other two answers as to how this actually works. I refer you to the C# specification section on object initializers, which clearly summarizes the semantics:

A member initializer that specifies a collection initializer after the equals sign is an initialization of an embedded collection. Instead of assigning a new collection to the field or property, the elements given in the initializer are added to the collection referenced by the field or property.

Remember, the specification is published for your convenience; if you have a question about the meaning of a C# language construct, it (or the printed annotated version "The C# Programming Language") should be your first reference.

like image 45
Eric Lippert Avatar answered Oct 12 '22 01:10

Eric Lippert