C# c中只读属性的对象初始值设定项#

C# c中只读属性的对象初始值设定项#,c#,projection,readonly,object-initializers,C#,Projection,Readonly,Object Initializers,如果你有这门课: class Foo { Bar Bar { get; } = new Bar(); } class Bar { string Prop {get; set; } } 可以使用对象初始化,如: var foo = new Foo { Bar = { Prop = "Hello World!" } } 如果你有课 class Foo2 { ICollection<Bar> Bars { get; } = new Lis

如果你有这门课:

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

class Bar {
      string Prop {get; set; }
}
可以使用对象初始化,如:

var foo = new Foo { 
    Bar = { Prop = "Hello World!" }
}
如果你有课

class Foo2 {
      ICollection<Bar> Bars { get; } = new List<Bar>();
}
但是,我想写一些

var items = new [] {"Hello", "World"};
var foo = new Foo2 { 
    Bars = { items.Select(s => new Bar { Prop = s }) }
}
但是,上面的代码不使用以下代码编译:

无法将IEnumerable分配给Bar

我不能写:

var foo = new Foo2 { 
    Bars = items.Select(s => new Bar { Prop = s })
}
属性栏是只读的


这可以存档吗?

bar={…}
不执行赋值。相反,它为初始值设定项中的每个项调用
Add
。这就是它不起作用的原因

这就是为什么
Bar=items.Select(s=>newbar{Prop=s})
会给出相同的错误:它是一个赋值,而不是要添加的列表


除了使用构造函数传递值,或者在构造函数运行后使用常规的
Add
AddRange
语句之外,没有其他选项。

bar={…}
不会进行赋值。相反,它为初始值设定项中的每个项调用
Add
。这就是它不起作用的原因

这就是为什么
Bar=items.Select(s=>newbar{Prop=s})
会给出相同的错误:它是一个赋值,而不是要添加的列表

除了使用构造函数传递值,或者在构造函数运行后使用常规的
Add
AddRange
语句之外,没有其他选项。

如果阅读实际的编译器错误(),您会发现集合初始值设定项对于
Add()
调用来说只是语法上的糖分:

CS1950:最佳重载集合初始化器方法
System.Collections.Generic.ICollection.Add(Bar)
具有一些无效参数

CS1503:参数
#1
无法将
系统.Collections.Generic.IEnumerable
表达式转换为类型
条形图

因此语法
SomeCollection={someItem}
将被编译为
SomeCollection.Add(someItem)
。您不能将
IEnumerable
添加到
Bar
s的集合中

您需要手动添加所有项目:

foreach (bar in items.Select(s => new Bar { Prop = s }))
{
    foo.Bars.Add(bar);
}
或者,如果您的目标是较短的代码,请在
Foo2
的构造函数中执行相同的操作:

public class Foo2 
{
    public ICollection<Bar> Bars { get; }
    
    public Foo2() : this(Enumerable.Empty<Bar>()) { }
    
    public Foo2(IEnumerable<Bar> bars)
    {
        Bars = new List<Bar>(bars);
    }
}
对于@jeroenmoster所设想的对集合初始值设定项语法的有趣滥用,您可以使用扩展方法:

public static class ICollectionExtensions
{
    public static void Add<T>(this ICollection<T> collection, IEnumerable<T> items)
    {
        foreach (var item in items)
        {
            collection.Add(item);
        }
    }
}
公共静态类ICollectionExtensions
{
公共静态无效添加(此ICollection集合,IEnumerable items)
{
foreach(项目中的var项目)
{
集合。添加(项目);
}
}
}
这使得:

public class Foo
{
    public ICollection<string> Bar { get; } = new List<string>();
}

var foo = new Foo
{
    Bar = { new [] { "foo", "bar", "baz" } }
};

    
公共类Foo
{
公共ICollection条{get;}=new List();
}
var foo=新foo
{
Bar={new[]{“foo”,“Bar”,“baz”}
};
但是这太糟糕了。

如果您阅读实际的编译器错误(),您会发现集合初始值设定项对于
Add()
调用来说只是语法上的糖分:

CS1950:最佳重载集合初始化器方法
System.Collections.Generic.ICollection.Add(Bar)
具有一些无效参数

CS1503:参数
#1
无法将
系统.Collections.Generic.IEnumerable
表达式转换为类型
条形图

因此语法
SomeCollection={someItem}
将被编译为
SomeCollection.Add(someItem)
。您不能将
IEnumerable
添加到
Bar
s的集合中

您需要手动添加所有项目:

foreach (bar in items.Select(s => new Bar { Prop = s }))
{
    foo.Bars.Add(bar);
}
或者,如果您的目标是较短的代码,请在
Foo2
的构造函数中执行相同的操作:

public class Foo2 
{
    public ICollection<Bar> Bars { get; }
    
    public Foo2() : this(Enumerable.Empty<Bar>()) { }
    
    public Foo2(IEnumerable<Bar> bars)
    {
        Bars = new List<Bar>(bars);
    }
}
对于@jeroenmoster所设想的对集合初始值设定项语法的有趣滥用,您可以使用扩展方法:

public static class ICollectionExtensions
{
    public static void Add<T>(this ICollection<T> collection, IEnumerable<T> items)
    {
        foreach (var item in items)
        {
            collection.Add(item);
        }
    }
}
公共静态类ICollectionExtensions
{
公共静态无效添加(此ICollection集合,IEnumerable items)
{
foreach(项目中的var项目)
{
集合。添加(项目);
}
}
}
这使得:

public class Foo
{
    public ICollection<string> Bar { get; } = new List<string>();
}

var foo = new Foo
{
    Bar = { new [] { "foo", "bar", "baz" } }
};

    
公共类Foo
{
公共ICollection条{get;}=new List();
}
var foo=新foo
{
Bar={new[]{“foo”,“Bar”,“baz”}
};

汉斯·帕桑特:这将给出一个无法分配给酒吧的列表。你必须走很长的路,调用
酒吧。如果你只有
ICollection
,那么为每个项目添加
。对象初始值设定项只是语法速记;C#通常对添加会增加运行时开销的语法持谨慎态度,并且更希望您能够明确地说明这一点(当然,这也有例外)。@Flater对我来说似乎是正确的。你认为哪一个是错的?@Diegrafaelsouza不,它是只读的。太多的语法糖会导致语言衰退。Foo2需要一个构造函数,这样您就可以初始化条。@Hans Passant:这将给出无法分配给条的列表。您必须走很长的路,调用
条。如果您只有
ICollection
,请为每个项添加
。对象初始值设定项只是语法速记;C#通常对添加会增加运行时开销的语法持谨慎态度,并且更希望您能够明确地说明这一点(当然,这也有例外)。@Flater对我来说似乎是正确的。你认为哪一个是错的?@Diegrafaelsouza不,它是只读的。太多的语法糖会导致语言衰退。Foo2需要一个构造函数,这样你就可以初始化条了。不,如果条不是只读的,第二个就可以了。它失败是因为它是只读的。我想添加选择器中的每一项。换句话说,这就是我所说的。因为它是赋值,所以属性不能是只读的。所以不要赋值,而是调用
Add
。@MichaWiedenmann:这是一个常规的对象初始值设定项,而不是集合初始值设定项。语法
Bar={Prop=…}
Bar={Prop}
不同,尽管表面上相似。对于对象初始值设定项来说,
Bar
是否为只读并不重要,只要
Prop
是可写的——它不指定新的
Bar
。这是在中记录的,因此应该