简体   繁体   English

为什么必须显式声明嵌套类型?

[英]Why the nested type must be explicitly declared?

I think this is the first time I'm using the new C#6 dictionary-initialization feature, and I need a nested structure like the below one: 我认为这是我第一次使用新的C#6字典初始化功能,我需要一个如下所示的嵌套结构:

        var map = new Dictionary<string, Dictionary<string, object>>()
        {
            ["WNodeScramblingResetZone_Unlock"] = 
            {
                ["updater"] ="pinco",
                ["rdlev"] = 55
            },
            ["WNodeScramblingResetZone_NewPwd"] = 
            {
                ["updater"] ="pallo",
                ["wrlev"] = 75,
                ["is_online"] = true
            }
        };

This syntax seems fine: no compilation errors. 这种语法似乎很好:没有编译错误。 However, when the program starts I see a couple of "KeyNotFoundException" errors in the output window, and the application does not work. 但是,当程序启动时,我在输出窗口中看到一些“KeyNotFoundException”错误,并且应用程序不起作用。

By the way, if I explicitly declare the nested type instantiation, everything runs fine. 顺便说一句,如果我显式声明嵌套类型实例化,一切运行正常。

        var map = new Dictionary<string, Dictionary<string, object>>()
        {
            ["WNodeScramblingResetZone_Unlock"] = new Dictionary<string, object>()
            {
                ["updater"] ="pinco",
                ["rdlev"] = 55
            },
            ["WNodeScramblingResetZone_NewPwd"] = new Dictionary<string, object>()
            {
                ["updater"] ="pallo",
                ["wrlev"] = 75,
                ["is_online"] = true
            }
        };

Is that a limitation, a bug, or rather there is a concrete reason to define it? 这是一个限制,一个错误,还是有一个具体的理由来定义它?

When you write code like this: 当你编写这样的代码时:

var map = new Dictionary<string, Dictionary<string, object>>()
{
    ["WNodeScramblingResetZone_Unlock"] = 
    {
        ["updater"] ="pinco"
    }
};

It's compiled into the equivalent of this: 它被编译成相当于:

var map = new Dictionary<string, Dictionary<string, object>>()
map["WNodeScramblingResetZone_Unlock"]["updater"] = "pinco";

It does not create any instances that you didn't explicitly specify. 它不会创建您未明确指定的任何实例。

This is code that could work (which is why it's allowed) for some dictionary-like class, which returns empty collection for keys that don't exist, but will indeed cause KeyNotFoundException for Dictionary . 这是代码可以工作(这就是为什么它是允许的),对于一些类似于字典的类,它返回空的集合不存在的键,但确实会导致KeyNotFoundExceptionDictionary

On the other hand, this code: 另一方面,这段代码:

var map = new Dictionary<string, Dictionary<string, object>>()
{
    ["WNodeScramblingResetZone_Unlock"] = new Dictionary<string, object>()
    {
        ["updater"] ="pinco"
    }
};

Is compiled as: 编译为:

var map = new Dictionary<string, Dictionary<string, object>>();
var tmp = new Dictionary<string, object>();
tmp["updater"] = "pinco";
map["WNodeScramblingResetZone_Unlock"] = tmp;

As you can see, this calls the map["WNodeScramblingResetZone_Unlock"] setter with a new instance (instead of the getter in the previous version), which is why it works. 正如您所看到的,这将使用新实例(而不是之前版本中的getter)调用map["WNodeScramblingResetZone_Unlock"] setter ,这就是它工作的原因。

I used http://tryroslyn.azurewebsites.net/ to translate this C# code into VB.NET: 我用http://tryroslyn.azurewebsites.net/将这个C#代码翻译成VB.NET:

Public Class Program
    Public Shared Sub Main()
        Dim expr_06 As Dictionary(Of String, Dictionary(Of String, Object)) = New Dictionary(Of String, Dictionary(Of String, Object))()
        expr_06("x")("updater") = "pinco"
        expr_06("x")("rdlev") = 55
        expr_06("y")("updater") = "pallo"
        expr_06("y")("wrlev") = 75
        expr_06("y")("is_online") = True
    End Sub
End Class

It cleary shows that new dictionaries are not created only accessed by key. 它清晰地表明,新的词典不是仅通过密钥访问而创建的。 The new [key] = value syntax compiles to dictionary[key] = value not like old one {key, value} which compiled to dictionary.Add(key, value) . 新的[key] = value语法编译为dictionary[key] = value而不是像编译为dictionary.Add(key, value)旧的{key, value}

I think this is a feature, compiler doesn't know what type of IDictionary you need so you must provide concrete type. 我认为这是一个功能,编译器不知道你需要什么类型的IDictionary ,所以你必须提供具体的类型。 There is also posibility that you use some dynamic collection that automatically creates subdictionnaries on first access in that case this code would work. 您还可以使用一些动态集合,在第一次访问时自动创建子代码,此代码可以使用。 As you may see compiler leaves you great freedom to do what you want at the expense of program verbosity. 正如您所看到的,编译器让您可以自由地以牺牲程序详细程度为代价来执行您想要的操作。

EDIT: I write a bit lengthy blog post about initializers that provides a more deep explanation 编辑:我写了一篇关于初始化器的博客文章 ,提供了更深入的解释

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么必须在foreach C#中显式声明ListItem - Why ListItem must be declared explicitly in foreach C# 为什么我必须重命名枚举参数到其声明的类型? - why must I recast an enum parameter to its declared type? 为什么Visual C#2008编译器认为显式声明和引用的类型是另一种未引用的类型? - Why would the Visual C# 2008 Compiler think one explicitly declared and referenced type is another unreferenced one? 为什么不能明确声明在命名空间中定义的元素? - Why elements defined in a namespace cannot be explicitly declared? 为什么我必须显式提供泛型参数类型而编译器应该推断类型? - Why must I provide explicitly generic parameter types While the compiler should infer the type? 为什么.NET List Sort()不采用显式声明的委托对象? - Why does .NET List Sort() not take an explicitly declared delegate object? 为什么对显式声明的引用返回值有可空性警告? - Why is there nullability warning for explicitly declared reference return value? C#为什么必须将转换运算符声明为static和public? - C# why must conversion operator must be declared static and public? CS8983 具有字段初始值设定项的“结构”必须包含显式声明的构造函数 - CS8983 A 'struct' with field initializers must include an explicitly declared constructor 固定语句中声明的局部类型必须是指针类型 - The type of a local declared in a fixed statement must be a pointer type
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM