Предполагая, что у меня есть следующий код:

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

Будет выполнен и вызовет конструктор LoginViewModel, даже если я не вызвал клавишу «LoginView» в любой другой части моей программы.

-1
monogate 7 Сен 2016 в 21:03

5 ответов

Лучший ответ

Компилятор сначала создает конструктор (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());

Не полностью ясно, в чем заключается ваша путаница, но, по сути, весь этот код создает экземпляры объектов.

0
David 7 Сен 2016 в 18:14

ПРИМЕЧАНИЕ . Когда вы инициализируете словарь, да, он вызовет конструктор модели представления. Если вы хотите, чтобы это происходило при доступе к словарю, вы можете создать словарь типа <string, Func<ViewModel>> и просто вызовите функцию, которая вернет новую модель просмотра () => {new ViewModel();}

Есть несколько способов инициализировать словарь в c #

  1. Вы можете использовать синтаксис, который вы используете, который создаст словарь, а затем инициализирует значения с помощью add.

    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;
    }
    
  2. Вы можете создать его с помощью инициализаторов, как в C # 5 и более ранних версиях:

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

    Примечание , это рискованно, потому что вы можете инициализировать словарь с тем же ключом, что приведет к ошибке.

Этот способ под капотом вызывает метод Add, что еще более интересно, так это то, что вы можете перегрузить метод Add, чтобы изменить способ добавления вещей в словарь, то есть если вы создадите перегрузку для Add, которая принимает (int, ViewModelBase) и скажет вы вызвали int.ToString () внутри, вы также можете использовать int в инициализаторе.

  1. В C # 6.0 и выше появился новый способ инициализации словарей, который выглядит следующим образом:

    Dictionary<string, Customer> cList = new Dictionary<string, Customer>()
    {
       ["LoginView"] = new LoginViewModel(),
       ["SignUpView"] = new SignUpViewModel()
    };
    

Преимущество использования этого способа заключается в том, что если вы добавите в словарь запись с тем же значением, она переопределит старое значение и не вызовет ошибку, вы можете найти дополнительную информацию об этом здесь

1
johnny 5 7 Сен 2016 в 18:21

Да, выражение tempDictionary.Add ("LoginView", new LoginViewModel ()); создаст новый экземпляр класса LoginViewModel , даже если вы никогда не пытались получить доступ к LoginView для объекта словаря tempDictionary .

0
Botond Botos 7 Сен 2016 в 18:15

Уходя от вашего комментария:

@Jonesopolis Я просто хочу знать, есть ли этот код:

tempDictionary.Add("LoginView", new LoginViewModel()); 

будет выполнен и вызовет конструктор LoginViewModel, даже если я не вызвал клавишу «LoginView» в любой другой части моей программы.

Этот код такой же, как:

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

Сначала выполняется выражение, конструирующее объект (new LoginViewModel()), затем результирующее значение передается в метод Add словаря. Итак, да, ваш объект создается перед передачей в словарь.

Вы можете написать очень простую программу, чтобы проверить это самостоятельно.

0
Jonesopolis 7 Сен 2016 в 18:16

Я просто хочу знать, есть ли этот код:

tempDictionary.Add("LoginView", new LoginViewModel());

будет выполнен и вызовет конструктор LoginViewModel, даже если я не вызвал клавишу «LoginView» в любой другой части моей программы.

Да, конструктор вызывается прямо здесь, в коде. Если вы хотите отложить их загрузку, можете попробовать 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, когда мы инициализируем класс внутри как значение?

Я считаю, что вы имеете в виду под «классом внутри» то, что ваш тип Dictionary<string, ViewModelBase> содержит тип ViewModelBase как второй общий тип. Тип Dictionary<T,U> - это общий тип, для которого в C # действуют особые правила. C # не вызывает конструктор типа T или U при вызове конструктора Dictionary<T, U>, он просто понимает информацию типа о T и о {{X7 }}, чтобы среда выполнения знала, как обращаться с объектами, хранящимися в словаре, когда вы позднее на них ссылаетесь.

В основном универсальные типы (в вашем случае я имею в виду string и ViewModelBase) являются заполнителями для среды выполнения, и способ работы с ними в C # заключается в том, что при использовании универсального среда выполнения должна иметь возможность чтобы выяснить, как с ними обращаться, независимо от того, какой тип используется при создании экземпляра универсального типа. Это означает, что даже если бы это имело смысл, конструктор Dictionary<T,U> не может вызывать new ViewModelBase() выше, потому что не все типы имеют конструктор! (Например, ICloneable). В C # тип - это просто некоторая информация, которую он знает об объекте, которую он использует как во время компиляции, так и во время выполнения, чтобы определить, что делать с этим.

Компилятор сначала создает конструктор (ctor без параметров) и только потом добавляет мои KeyValuePairs?

Неа. Вы пишете конструкторы и вызываете конструкторы. C # неявно вызывает конструкторы только в редких случаях (например, с использованием отражения).

0
Community 20 Июн 2020 в 09:12