C#当我们将一个类初始化为一个值时,Dictionary如何工作?

时间:2016-09-07 18:03:16

标签: c# dictionary

假设我有以下代码:

public static Dictionary<string, ViewModelBase> LoadDictionary()
{
    Dictionary<string, ViewModelBase> tempDictionary = new Dictionary<string, ViewModelBase>();
    tempDictionary.Add("LoginView", new LoginViewModel());
    tempDictionary.Add("SignUpView", new SignUpViewModel());
    tempDictionary.Add("ContactListView", new ContactListViewModel());
    return tempDictionary;
}

我指的是这一行:

Dictionary<string, ViewModelBase> tempDictionary = new Dictionary<string, ViewModelBase>();

编译器是否首先创建一个构造函数(无参数ctor),然后才添加我的KeyValuePairs?

如果是这样,我的参数ctor将如何(LoadDictionary)?

与这篇文章相关的最重要的问题是:

当我添加 KeyValuePairs 时,是否还实例化还是等待调用然后实例化?

我的意思是:

new LoginViewModel()
new SignUpViewModel()
new ContactListViewModel()


修改

我只想知道是否

tempDictionary.Add("LoginView", new LoginViewModel());
即使我没有在程序的任何其他部分调用“LoginView”键,也会执行

并调用LoginViewModel构造函数。

5 个答案:

答案 0 :(得分:1)

注意当您初始化词典时,它将调用视图模型的构造者,如果您希望在访问词典时发生,则可以创建类型{{1的词典并调用一个函数,该函数将返回一个新的ViewModel <string, Func<ViewModel>>

有几种方法可以在c#

中初始化字典
  1. 您可以使用您正在使用的语法创建字典,然后使用add初始化值。

    () => {new ViewModel();}
  2. 您可以使用初始化程序创建它,C#5和旧方法将是这样的:

    public static Dictionary<string, ViewModelBase> LoadDictionary()
    {
        Dictionary<string, ViewModelBase> tempDictionary = new Dictionary<string, ViewModelBase>();
        tempDictionary.Add("LoginView", new LoginViewModel());
        tempDictionary.Add("SignUpView", new SignUpViewModel());
        tempDictionary.Add("ContactListView", new ContactListViewModel());
        return tempDictionary;
    }
    

    注意这是有风险的,因为您可以使用相同的键初始化字典,这将导致错误

  3. 这种方式在引擎下调用Add方法更有趣的是你可以重载Add方法来修改你向字典中添加东西的方式,这意味着如果你为Add创建一个重载,那就是(int,ViewModelBase)并且你说你在内部调用了int.ToString(),你也可以在初始化器中使用int。

    1. 在C#6.0及更高版本中,有一种初始化字典的新方法,如下所示:

      public static Dictionary<string, ViewModelBase> LoadDictionary()
      {
           return new Dictionary<string, ViewModelBase>() { 
               {"LoginView", new LoginViewModel()},
               {"SignUpView", new SignUpViewModel()}, 
               {"ContactListView", new ContactListViewModel()} 
           };
      }
      
    2. 使用这种方式的好处是,如果您向字典添加具有相同值的条目,它将覆盖旧值并且不会导致错误,您可以在其上找到更多信息here

答案 1 :(得分:0)

  

编译器是否首先创建一个构造函数(无参数ctor),然后才添加我的KeyValuePairs?

编译器不必创建任何东西。 Dictionary<>有一个无参数构造函数,您在此处调用:

new Dictionary<string, ViewModelBase>();

您只是调用构造函数,不传递任何参数,并返回Dictionary<string, ViewModelBase>的实例。

  

当我添加我的KeyValuePairs时,值是否也被实例化了?

它们是实例化的,因为你要实例化它们:

new LoginViewModel()

与任何其他构造函数一样,这将创建该类的新实例。

请注意,您显示的代码中没有任何代码与类初始值设定项有任何关系。集合类型的初始化程序(如Dictionary<>)可能如下所示:

Dictionary<string, ViewModelBase> tempDictionary = new Dictionary<string, ViewModelBase>() { 
     {"LoginView", new LoginViewModel()},
     {"SignUpView", new SignUpViewModel()}, 
     {"ContactListView", new ContactListViewModel()} 
 }

编译的基本上与你所拥有的相同:

Dictionary<string, ViewModelBase> tempDictionary = new Dictionary<string, ViewModelBase>();
tempDictionary.Add("LoginView", new LoginViewModel());
tempDictionary.Add("SignUpView", new SignUpViewModel());
tempDictionary.Add("ContactListView", new ContactListViewModel());

答案 2 :(得分:0)

是的, tempDictionary.Add(&#34; LoginView&#34;,新的LoginViewModel()); 表达式将创建 LoginViewModel 类的新实例,即使您从未尝试访问 tempDictionary 字典对象的 LoginView 键。

答案 3 :(得分:0)

取消你的评论:

  

@Jonesopolis我只想知道这段代码:

tempDictionary.Add("LoginView", new LoginViewModel()); 
  即使我没有在程序的任何其他部分调用“LoginView”键,也会执行

并调用LoginViewModel构造函数。

此代码与:

相同
var vm = new LoginViewModel();
tempDictionary.Add("LoginView, vm);

首先执行构造对象(new LoginViewModel())的表达式,然后将结果值传递到字典上的Add方法。所以,是的,你的对象在被传递到字典之前被构造。

你可以编写一个非常简单的程序来自己测试一下。

答案 4 :(得分:0)

  

我只想知道这段代码:

tempDictionary.Add("LoginView", new LoginViewModel());
     即使我没有调用&#34; LoginView&#34;也会执行

并调用LoginViewModel构造函数。键入我的程序的任何其他部分。

是的,然后在代码中调用构造函数。如果你想延迟加载它们,你也可以尝试Lazy<T>类。

var deferredConstructionDict = new Dictionary<string, Lazy<ViewModelBase>>();
deferredConstructionDict.Add("LoginView", new Lazy<ViewModelBase>(() => new LoginViewModel()));
deferredConstructionDict.Add("SignUpView", new Lazy<ViewModelBase>(() => new SignUpViewModel()));
deferredConstructionDict.Add("ContactListView", new Lazy<ViewModelBase>(() => new ContactListViewModel()));

然后通过访问“字典”值的Value属性来获取模型。

var modelKey = "LoginView";
var myModelFromKey = deferredConstructionDict[modelKey].Value;

原始邮件:

我认为你的问题存在一个根本性的误解,而其他答案并没有解决这个问题。

  

当我们将一个类作为值初始化时,Dictionary如何工作?

我相信你的意思是&#34;在&#34;是Dictionary<string, ViewModelBase>类型包含类型ViewModelBase作为第二种泛型类型。 Dictionary<T,U>类型是泛型类型,在C#中有特殊规则。当C#调用T的构造函数时,它不会调用UDictionary<T, U>类型的构造函数,它只会理解有关T和{{{}}的类型信息{1}}以便运行时知道如何在以后引用时处理存储在字典中的对象。

基本上泛型类型(在你的情况下我指的是Ustring)是运行时的占位符,C#处理它们的方式是当使用泛型时,在创建泛型类型的实例时,运行时应该能够弄清楚如何处理它们无论使用什么类型。这意味着,即使这样做有意义,ViewModelBase构造函数也无法调用Dictionary<T,U>,因为并非所有类型都有构造函数! (例如new ViewModelBase())。在C#中,a type is simply some information it knows about an object它在编译和运行时使用它来确定如何处理它。

  

编译器是否首先创建一个构造函数(无参数ctor),然后才添加我的KeyValuePairs?

不。你编写构造函数,然后调用构造函数。 C#仅在极少数情况下隐式调用构造函数(例如,使用反射)。