我一直在用一些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!"
一条语句:通常是一个表达式,后跟一个
;
,但类似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));
很好。运作方式
每个操作都采用任意数量的操作数,然后可选地输出某些内容。例如,乘法运算接受两个操作数-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/