c# - 您不需要将对象名称传递给构造函数吗? “new Class()”还不是对象

标签 c# object inheritance composition

我一直在用一些Udemy课程来补充我的学校课程工作。我现在正在尝试理解中间C#的一个示例,我对其中一个细节有些困惑。我了解继承,但是对组合(具体是将对象传递到对象以及在哪里初始化)感到有些困惑。在此示例中,有一个DbMigrator类,Installer类以及一个Logb类,DbMigrator和Installer都从中借鉴。这是主要的:

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


我了解在其中创建传递到安装程序对象的记录器对象的部分,但是我没有获得dbMigrator对象的“ new Logger()”构造函数,因为没有正在创建的记录器的变量名。您是否不需要在dbMigrator对象的构造函数中创建“ var logger1 = new Logger()”?我不明白如何不带变量名就传递“ new 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类已经初始化了,但是我认为需要首先创建一个对象。

有人可以帮我清理一下吗?

最佳答案

因此,首先,对问题进行总结-这是如何工作的?

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


不是吗

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


详细的答案很长,因此,我将尽力使它易于理解。首先,我们将描述表达式是什么以及它们在C#中的工作方式(更广泛地讲,它们如何在任何基于堆栈的语言中工作-幸运的是,这几乎就是您所知道的所有内容!)

表达式,语句和操作..什么?

一个操作:类似加,减等。

表达式:一堆操作。 1+2+3或只是一个常量,例如1"hi!"

一条语句:通常是一个表达式,后跟一个;,但类似ifwhile循环的语句也是这样。如果程序是烹饪食谱,则声明只是步骤之一。

让我们快速浏览一下C#:

int totalPrice=1+2*3;


那是一条语句,它被分解成这样的操作:


2乘以3
加1
将结果设置为名为totalPrice的局部变量


此时要问的一个大问题是:

那么Multiply 2 by 3运行后,6存放在哪里?

答:堆栈。不久之后会更多!

关于方法的快速补充说明

Hello("all!");这样的方法调用将表达式作为参数。 Hello(1+1;);失败,因为那是其中的一条语句。 Hello(1+(2*3));很好。

运作方式

每个操作都采用任意数量的操作数,然后可选地输出某些内容。例如,乘法运算接受两个操作数-A * B-然后将它们相乘的结果输出。 new Something()接受任意数量的构造函数参数,并输出对新创建对象的引用。

这是重要的部分。

操作的输出始终进入堆栈。输入总是总是也首先放入堆栈。

那么这是什么东西呢?

完整的stack machine在这里超出范围-如果您对完整的详细信息感兴趣,请查看例如this wikipedia article。快速总结是所有基于C的语言都使用相同的概念。让我们回顾一下上面的C#语句,并在堆栈操作中对其进行描述:

int totalPrice=1+2*3;



将2推入堆栈

堆栈现在只有[2]
将3推入堆栈

堆栈现在为[2,3]
乘法(从堆栈中取出两个值并将它们相乘)

现在的堆栈是[6]
将1推入堆栈

堆栈现在为[6,1]
加(从堆栈中剔除两个值,将它们加在一起)

现在的堆栈是[7]
存储在本地totalPrice中(弹出堆栈值并将其存储)

堆栈现在为空


旁注:这些堆栈操作是C#编译器生成的。它称为CIL or .NET IL

调用栈

健康警告!调用堆栈完全不同。调用堆栈可能会“溢出”。

那原始的陈述呢?

好吧,希望我们已经为这一部分覆盖了足够的基础,使之更有意义!因此,让我们采用原始语句:

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


首先,new操作与其他任何方法调用一样-将所有参数都压入堆栈,调用该方法(将所有参数从堆栈中弹出),然后将返回值放在堆栈中。

因此,这里描述了堆栈样式:


新的Logger对象(在堆上创建Logger对象,并在堆栈上放置对它的引用。没有args,因此它不会弹出任何东西)

堆栈现在是[记录器参考]
新的DBMigrator对象(关闭1 arg,推送引用)

堆栈现在是[DBMigrator参考]
存储在本地dbMigrator

堆栈现在为空


要真正巩固这一点,请将其与替代方法进行比较(这也是有效的):

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



新记录器对象

堆栈现在是[记录器参考]
存储在本地logger

堆栈现在为空
加载本地logger

堆栈现在是[记录器参考]
新的DbMigrator对象

堆栈现在是[DBMigrator参考]
存储在本地dbMigrator

堆栈现在为空


您还刚刚学到了什么:它们都可以工作,但是第二个要慢一些-它可以完成更多工作。查看这些堆栈操作,似乎完全没有意义-就像您只是将文件放入文件柜中,然后立即将其取出一样!

什么时候应该在堆栈上使用本地语言?

快速说明一下,有些语言没有本地语言,只使用堆栈。它们可以进行极大的优化并趋于更快地运行,但也很难编写。当您需要对某物的多个引用时,本地人非常有用:

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


如果只使用一次,那么这也是完全有效的:

(new Logger()).A();


奖励回合:假设方法A做了return this;,导致再次在堆栈上引用了该Logger对象。这将使我们做到这一点:

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


这就是方法链-它与函数式编程有关,并且由于它的紧凑性而变得越来越普遍。

摘要

局部变量不是存储事物的唯一方法-堆栈也是如此!您不需要跟踪堆栈-编译器会为您完成所有这些工作。您只需要考虑这些输入/输出值。

关于c# - 您不需要将对象名称传递给构造函数吗? “new Class()”还不是对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42057640/

相关文章:

java - 在抽象类中创建方法而不是在扩展它的类中重写它们是一个好习惯吗?

c# - 更改文件的属性表

c# - 如何从多个文本框中插入的值生成子字符串值

javascript - 如何在 javascript 中将对象的普通数组转换为多级数组?

javascript - 解析云代码访问对象

java - 为什么当我使用实例方法返回另一个对象时,我当前的对象被修改了? - java

java - Jackson 通过继承进行反序列化

javascript - 在 Object.defineProperty 中调用父级实现

c# - 将 ArrayList 的元素移动到前面,同时保持顺序 C#

c# - Asp.net 菜单导航事件类属性