[英]What is the difference between these two method calls in c#?
例如,我有一个带有一个void
方法的类。
这是我的课:
class MyClassTest
{
public void Print()
{
Console.WriteLine("Hello");
}
}
我是新手,有点困惑,这两个方法调用之间有区别吗?
这是我的主要方法
static void Main(string[] args)
{
//first call
MyClassTest ms = new MyClassTest();
ms.Print();
//second call
new MyClassTest().Print();
}
在下面的情况下,当您要保留对已构造对象的引用并稍后对其执行一些进一步的操作时,将需要执行此操作。
MyClassTest ms = new MyClassTest();
ms.Print();
而在下面的情况下, 仅当您不再关心构造后的构造对象,而只是对调用方法Print
感兴趣时, 才需要这样做。
new MyClassTest().Print();
这两种情况之间的细微差别是,在被引用的对象执行进一步操作的情况下,它很可能比不再引用的对象更晚被销毁,例如,上面的第二个示例(GC(垃圾收集器)会发现)它没有参考,因此决定摆脱它。
实际上没有什么区别。 当需要在程序中进一步引用MyTestClass
时,可以使用第一种情况。 您将第二种情况用作“ fire-and-forget
。 如果您计划大量使用第二种情况,建议将Print
方法设置为static
。
IL代码没有任何区别,只是将变量保持引用加载到堆栈上时使用stloc.0
方法( stloc.0
和ldloc.0
IL指令):
MyClassTest ms = new MyClassTest();
ms.Print();
new MyClassTest().Print();
您的两个调用在c#中执行相同的语义操作:不同之处在于,在您的第一个调用中,您创建了ms
变量,这向读者表明您的意图是在代码中再次使用它:实际上,您正在调用ms.Print()
之后。
您的第二次调用未声明任何变量,这意味着您的意图恰恰是在代码中仅对全新的MyClassTest
实例调用一次Print
方法,并且您并不关心刚刚创建的实例。
旁注:在发布模式下编译时,C#编译器将压缩并减少变量使用,因此,您的两个调用将以相同的方式进行编译,就像您的第二个调用一样。
在这种特殊情况下,不会。
每当您根据另一个方法调用, new
,属性访问等结果调用一个方法时,请按照以下步骤操作:
new MyClassTest().Print();
这类似于您是否做过:
var temp = new MyClassTest()
temp.Print();
因此,在这种情况下,您的两个示例是相同的。
有一些变体,它们有所不同。
一种是从数组或字段访问中访问的值类型对象。 在这里,访问可能使用实际对象的地址,而不是进行复制。 现在有可能发生相反的情况,而不是创建一个隐式的临时局部并删除显式的局部,但这是不能保证的。 请注意,在使用可变值类型的情况下,带有和不带有临时本地变量的代码在这些情况下在语义上也不相同(但对于更接近您的示例的情况而言,其中对象是方法调用的结果,而不是ref return
到ref
变量)。
另一个是当它处于使用yield
或async
方法的内部时。 在这里,您方法中的本地变量成为生成的对象中的字段(该对象实现IEnumerable<T>
和/或IEnumerator<T>
yield
或Task
async
),而我上面描述的“不可见”临时本地变量则没有。 (编译器可以并且将来可能会做得更好,以消除在yield
或async
调用之后不存在的某些内容,因此实际上并不一定要是字段,但是暂时当地人成为田野)。
因此,在某些情况下,对它们进行一次简单操作的显式局部语言与直接对获取值的方式进行操作的情况有时会有所不同,尽管您的示例并非其中之一。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.