此列表分配如何工作? [英] How Does This List Assignment Work?

查看:22
本文介绍了此列表分配如何工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我看过这个代码示例,它看起来像是为列表分配了一个数组初始值设定项.我认为它不起作用,但它以某种方式编译.{} 不是数组初始值设定项吗?儿童是 IList 类型.如果没有大括号前的新列表",它如何工作?

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 }
        };

当我尝试 Children = new List{ nameLabel, twitterLabel } 时,编译器给出了这个警告:无法分配属性或索引器 Layout.Children,它被读取-只要."

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."

顺便说一下,代码片段来自 Xamarin:https://developer.xamarin.com/guides/xamarin-forms/getting-started/introduction-to-xamarin-forms/

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

推荐答案

这是集合初始值设定项的特殊情况.

That's a special case of a collection initializer.

在 C# 中,数组初始值设定项的花括号已被通用化以适用于任何集合类构造函数.

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

任何类都支持那些实现了System.Collections.IEnumerable 并且有一个或多个Add() 方法的类.Eric Lippert 有一篇关于这种模式匹配"的好帖子.在 C# 中:编译器在这里做的是他们所谓的鸭子打字",而不是传统的强类型 OOP,其中类的功能是基于继承和接口实现来识别的.C# 在几个地方做到了这一点.那篇文章中有很多我不知道的东西.

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}");
    }
}

然后编译:

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

这是语法糖:

var f = new Foo();

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

你可以用这些玩一些非常奇怪的游戏.我不知道全力以赴是否是个好主意(实际上我确实知道——不是),但你可以.我编写了一个命令行解析器类,您可以在其中通过集合初始值设定项定义选项.它有十多个带有不同参数列表的 Add 重载,其中许多是通用的.编译器能推断出的任何东西都是公平的游戏.

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();
}

现在...

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

{ 0, "Beringia";}Bar 为自己创建的 Foo 实例的集合初始值设定项;这是语法糖:

{ 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");

编译器愿意解决语法糖初始化器用法中 Foo.Add() 的重载,当你这样看时是有道理的.我认为能够做到这一点很棒,但我对他们选择的语法并不是 100% 满意.如果你发现赋值运算符是一个红鲱鱼,其他人也会如此.

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" };
}

所以...

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

实际上变成了……

var b = new Bar();

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

我们不能初始化 Bar.Baz 因为它没有 setter,但是我们可以初始化它的属性,就像我们可以初始化 Foo 中的项目一样.即使它们已经被附加到实际构造函数的不同对象初始值设定项初始化,也是如此.

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.

集合初始值设定项,如您所料,是累积的​​:Bar.Foo 将包含三个项目:{ "1000", "0", "Beringia";}.

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

当您将花括号视为一列赋值语句或 Add() 重载调用的简写时,它们都会成为焦点.

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.

这是我从 Eric Lippert 的那篇文章中了解到的另一个模式匹配功能/a>:

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;
    }
}

因此...

var x = from s in HoldMyBeerAndWatchThis select s;

要使 select 工作,您所需要的只是您从中选择的东西必须有一个名为 Select 的方法,该方法返回类似的东西 IEnumerable 如@EricLippert 在 链接文章(感谢 Eric!),并采用 Func 参数.

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.

这篇关于此列表分配如何工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆