协变对象初始值设定项?

发布于 2024-10-13 07:49:02 字数 352 浏览 5 评论 0原文

假设我有一个类,它的属性是字典,使用对象初始值设定项我可以使用此语法(我认为看起来很干净):

new MyClass()
{
  Table = { {"test",true},{"test",false} }
}

但是,在初始值设定项之外我无法执行此操作:

this.Table = { {"test",true},{"test",false} };

为什么初始化器是一种特殊情况?我大胆猜测它与 LINQ 要求、协方差或其他什么有关,但感觉有点不一致,不能在任何地方使用这种初始化程序......

say that I have an class that has a property that is a dictionary<string,bool>, using a object initializer I can use this syntax (which I think looks pretty clean):

new MyClass()
{
  Table = { {"test",true},{"test",false} }
}

however, outside of the initializer I can't do this:

this.Table = { {"test",true},{"test",false} };

Why are initializers a special case? I'd hazard a guess that it has something to do with LINQ requirements, covariance or whatnot but it feels a little incongruent not being able to use that kind of initializer everywhere...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

梦毁影碎の 2024-10-20 07:49:02

这个问题有点令人困惑,因为这个问题与 LINQ 无关,与泛型方差无关,并且具有集合初始值设定项以及对象初始值设定项。真正的问题是,据我所知,“为什么在对象创建表达式之外使用集合初始值设定项是不合法的?

这里的相关设计原则是,一般来说,我们想要操作创建并初始化对象以在其中某处包含“new”一词,作为向读者发出的信号,表明此处正在创建对象。 (是的,C# 中这条规则有一些例外。作为对读者的练习,看看您是否能说出所有这些例外。)按照

您的方式做事会使推理代码变得更加困难。快点,这是做什么的?

d = new List<int>() { 10, 20, 30 };
d = { 40, 50, 60 };

第二行是否将 40、50、60 添加到现有列表中?还是用新列表替换旧列表?那里没有“new”,那么读者是否期望创建一个新对象?

当你说

q = new Whatever() { MyList = { 40, 50, 60 } };

这不会创建一个新列表时;它将 40, 50, 60 添加到构造函数分配的现有列表中。因此,您提出的语法对于是否创建新列表而言是不明确且令人困惑的。

提议的功能既令人困惑又不必要,因此不太可能很快实现。

The question is somewhat confusing, as the question has nothing to do with LINQ, nothing to do with generic variance, and features a collection initializer, as well as an object initializer. The real question is, as far as I can tell "why is it not legal to use a collection initializer outside of an object creation expression?"

The relevant design principle here is that in general, we want operations that create and initialize objects to have the word "new" in them somewhere as a signal to the reader that there is an object creation happening here. (Yes, there are a few exceptions to this rule in C#. As an exercise to the reader, see if you can name them all.)

Doing things your way makes it harder to reason about the code. Quick, what does this do?

d = new List<int>() { 10, 20, 30 };
d = { 40, 50, 60 };

Does the second line append 40, 50, 60 to the existing list? Or does it replace the old list with a new one? There's no "new" in there, so does the reader have an expectation that a new object has been created?

When you say

q = new Whatever() { MyList = { 40, 50, 60 } };

that doesn't create a new list; it appends 40, 50, 60 to an existing list allocated by the constructor. Your proposed syntax is therefore ambiguous and confusing as to whether a new list is created or not.

The proposed feature is both confusing and unnecessary, so it's unlikely to be implemented any time soon.

寄离 2024-10-20 07:49:02

这个限制比 LINQ 更古老。即使回到 C 语言中,您也可以编写

int numbers[5] = {1, 2, 3, 4, 5};

,但不能使用此语法为数组赋值。

我对 C# 中这背后的原因的猜测是,通常不应该对两个不同的对象使用相同的引用。如果您需要将一个新集合分配给现有引用,很可能您没有很好地设计代码,您可以在定义时初始化该集合,或者使用两个单独的引用而不是一个。

This limitation is far older than LINQ. Even back in C you could write

int numbers[5] = {1, 2, 3, 4, 5};

but you could not use this syntax to assign values to the array.

My guess about the reason behind this in C# is that usually you shouldn't use the same reference for two different objects. If you need to assign a new collection to an existing reference, most probably you didn't design your code very well, and you can either initialize the collection at definition, or use two separate references instead of one.

兮颜 2024-10-20 07:49:02

考虑到您的语法在运行时抛出 NullReferenceException - 您确定可以使用它吗?

public class Test
{
  public Dictionary<string, bool> Table {get; set;}
}

public void TestMethod()
{
  Test t = new Test { Table = { {"test", false} } }; //NullReferenceException
}

编译为以下内容(通过反射器):

Test <>g__initLocal3 = new Test();
<>g__initLocal3.Table.Add("test", 0.0M);

如您所见,Table 未初始化,因此在运行时产生 NullReferenceException

如果您在 Test 的构造函数中创建字典,则类初始值设定项会生成一系列 Add 语句,这是初始值设定项中的语法糖(对于 IEnumerable代码>s)。

由于我们无法看到或想象的不可预见的副作用,这可能没有在正常代码中引入。埃里克·利珀特也许能够提供帮助,因为他可能对手头的事情有更多的见解。

Considering your syntax throws a NullReferenceException at runtime - are you sure you can use it?

public class Test
{
  public Dictionary<string, bool> Table {get; set;}
}

public void TestMethod()
{
  Test t = new Test { Table = { {"test", false} } }; //NullReferenceException
}

This compiles to the following (via reflector):

Test <>g__initLocal3 = new Test();
<>g__initLocal3.Table.Add("test", 0.0M);

As you can see, Table isn't initialized, thus producing a NullReferenceException at runtime.

If you create the Dictionary in the ctor of Test, the class initializer produces a cascade of Add statements, which is syntactic sugar in the initializer (for IEnumerables).

This probably wasn't introduced for normal code due to unforseen side effects we can't see or imagine. Eric Lippert might be able to help out as he probably has more insight on the matter at hand.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文