2017-02-05 2 views
2

Я дополняю свою работу в школьном курсе некоторыми курсами Udemy. Я пытаюсь понять один пример прямо сейчас для промежуточного C#, и я немного смущен одной из деталей. Я понимаю наследование, но я немного запутался в композиции (в частности, передавая объекты объектам и где они инициализируются). В этом примере есть класс DbMigrator, класс Installer и класс Logger, с которого берутся DbMigrator и Installer. Вот Main:Вам не нужно имя объекта, которое нужно передать в конструктор? «new Class()» еще не является объектом

namespace Composition 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var dbMigrator = new DbMigrator(new Logger()); 
      var logger = new Logger(); 
      var installer = new Installer(logger); 

      dbMigrator.Migrate(); 
      installer.Install(); 
     } 
    } 
} 

Я понимаю ту часть, где вы создаете объект лесоруба, который передается на объект установщика, но я не получаю «новый Logger()» конструктор для объекта dbMigrator, потому что нет имя переменной для создаваемого регистратора. Вам не нужно было бы создать «var logger1 = new Logger()» внутри конструктора объекта dbMigrator? Я не понимаю, как вы можете просто передать «новый logger()» без имени переменной.

Вот класс DbMigrator:

namespace Composition 
{ 
    public class DbMigrator 
    { 
     private readonly Logger _logger; 
     public DbMigrator(Logger logger) 
     { 
      _logger = logger; 
     } 

     public void Migrate() 
     { 
      _logger.log = ("Blah blah blah"); 
     } 
    } 
} 

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

Может кто-нибудь прояснить это для меня?

+0

Я не совсем уверен, что понимаю ваш вопрос. Вы спрашиваете, почему, внутри класса и/или конструктора DbMigrator, прежде чем назначить '_logger = logger;', почему у вас нет '_logger = new Logger();'? Пожалуйста, постарайтесь уточнить, о чем именно вы спрашиваете. –

+1

'no object name for logger' - я думаю, вы не имеете в виду _variable_ для регистратора. Это не имеет значения - нет требования, чтобы у вас была локальная переменная, которая ссылается на объект. –

+0

Да, имя переменной для объекта. – schulzey

ответ

3

Итак, во-первых, резюме вопроса - как это работает?

var dbMigrator = new DbMigrator(new Logger()); 

Не так ли?

var logger = new Logger(); 
var dbMigrator = new DbMigrator(logger); 

Полностью подробный ответ довольно длинный, поэтому я постараюсь изо всех сил сделать его приятным и легким для подражания. Мы сделаем это, сначала опираясь на выражение и как они работают на C# (более широко, как они работают на любом языке на основе стека), к счастью, это почти все из тех, что вы слышали!)

Выражения, заявления и операции .. что?

Операция: Что-то вроде сложения, вычитания и т.д.

Выражение: кучу операций. 1+2+3 или просто константа, как 1 или "hi!"

заявление: Обычно одно выражения, за которым следует ; но что-то вроде if или while петли также заявление. Если программа была рецептом приготовления пищи, заявление является просто одним из этапов.

Давайте кратко рассмотрим, что в C#:

int totalPrice=1+2*3; 

Это одно заявление, и это разбита на операций как это:

  • Умножение 2, 3
  • Добавить 1
  • Задайте результат в локальной переменной, которая называется totalPrice

Отличный вопрос, чтобы спросить в этот момент, то это:

Так сразу после Multiply 2 by 3 трасс, где находится 6 хранится?

Стек. Подробнее об этом коротко!

Быстрых дополнительные замечания по методам

Метод требует как Hello("all!"); принимать выражения в качестве аргументов. Hello(1+1;); терпит неудачу, потому что это заявление там. Hello(1+(2*3)); в порядке хотя.

Операции

Каждая операция принимает в любом количестве операндов затем необязательно выводит что-то. Например, операция умножения занимает 2 операнда - A * B - затем выводит все, что было умножено вместе. new Something() принимает любое количество аргументов конструктора и выводит ссылку на вновь созданный объект.

Вот важная часть.

Выходной сигнал операции всегда поступает в стек. Входы также всегда помещаются в стек.

Так что это за штука?

Полный stack machine не входит в сферу действия здесь - если вас интересует полная информация, то проверьте, например. this wikipedia article. Краткое резюме - все языки на языке C используют эту же концепцию.Давайте вернемся, что C# заявление выше и описать его в операциях стека:

int totalPrice=1+2*3; 
  • Push 2 на стек

    Стек теперь только [2]

  • Нажмите 3 на стоп

    Стек теперь [2,3]

  • Умножить (Извлекает от двух значений из стека и умножает их)

    Стек теперь [6]

  • Нажмите 1 в стек

    Стек сейчас [6,1]

  • Добавить (Отбрасывает два значения из стека, добавляет их вместе)

    Стек теперь [7]

  • Хранить в локальной totalPrice (выскакивает от значения стека и сохраняет его)

    Стек теперь пуста

Замечание: эти операции стека - это то, что генерирует компилятор C#. Это называется CIL or .NET IL.

Вызов стека предупреждение

здоровья! Стол вызовов - это нечто совершенно другое. Это стек вызовов, который может «переполняться».

Как насчет оригинального заявления?

Хорошо, мы надеемся, что мы покрыли достаточно земли для этой части, чтобы иметь больше смысла! Итак, давайте оригинальное заявление:

var dbMigrator = new DbMigrator(new Logger()); 

Во-первых, new операция так же, как и любой другой метод вызова - все аргументы в стек, то вызывается метод (выскакивают их всех из стека) и возвращаемое значение затем помещается в стек.

Итак, здесь описывается стиль стека:

  • New Logger Object (Создает объект Logger на куче и помещает ссылку на него в стеке.Нет арг, так что ничего не поп)

    Stack теперь [ссылка регистратор]

  • New DBMigrator Object (Забирает 1 ARG прочь, толкает ссылку)

    стек Теперь [ссылка DBMigrator]

  • Хранить в местном dbMigrator

    Стек теперь пуст

Чтобы действительно цемент, который в, сравнить его с альтернативой (который также является действительным):

var logger = new Logger(); 
var dbMigrator = new DbMigrator(logger); 
  • Новый Logger Объект

    Stack в настоящее время [справочник по регистрации]

  • Хранить в местной logger

    Стек теперь пуст

  • нагрузки местного logger

    Stack теперь [ссылка регистратор]

  • Новый DbMigrator Объект

    Стек теперь [DBMig rator ссылка]

  • магазин в местном dbMigrator

    Стек теперь пуст

Что вы только что узнали: Они оба работают, но второй один немного медленнее - это больше. Глядя на эти операции с стеками, он, кажется, делает что-то совершенно бессмысленное. Это похоже на то, что вы просто положили что-то в шкафчик, а затем сразу же вытащили его снова!

Когда следует использовать местные жители над стеком?

В качестве быстрого примечания стороны, есть языки, которые не имеют местных жителей и используют стек. Они могут быть чрезвычайно оптимизированы и имеют тенденцию идти быстрее, но их также труднее написать.Местные жители являются большими, если вам нужно несколько ссылок на что-то:

Logger logger=new Logger(); 
// Using it twice! 
logger.A(); 
logger.B(); 

Если вы только с помощью его один раз, то это вполне допустимо также:

(new Logger()).A(); 

Бонус раунд: Допустим, что метод A сделал return this;, что привело к ссылке на этот объект Logger в стеке снова. Это будет позволять нам сделать это:

(new Logger()).A().B(); 

Это метод цепочки - это связано с функционального программирования и становится все более распространенным из-за того, как это компактный.

Резюме

Локальные переменные не единственный способ хранения вещей - стек делает это слишком! Вам не нужно отслеживать стек - компилятор делает все это для вас. Вам просто нужно подумать об этих значениях ввода/вывода.

+0

Отлично! Спасибо, что так ясно! – schulzey

+0

@schulzey проблем нет! Я попытался пойти с маршрутом, который должен был охватывать широкий диапазон языков помимо C# (Javascript, Java, C++, PHP и т. Д.) - все они делают то же самое) - надеюсь, все это имеет смысл! –

Смежные вопросы