例如,我有一些类,其中有一个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代码没有区别,除了WithInstance方法,当变量保持引用加载到堆栈上时(stloc.0
和ldloc.0
IL指令):
MyClassTest ms = new MyClassTest();
ms.Print();
new MyClassTest().Print();
你的两个调用在c#中执行相同的语义操作:区别在于你在第一次调用中创建了ms
变量,这表明你的意图是在你的代码中再次使用它:实际上你之后调用了ms.Print()
。
你的第二个调用,没有声明任何变量,这意味着你的意图恰好是在你的代码中只在一个全新的Print
实例上调用MyClassTest
方法,而你并不关心你刚创建的实例。
旁注:在发布模式下编译时,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
调用之后不存在的一些,因此实际上不必是字段,但暂时都是当地人成为田地)。
因此,有些情况下,对它们进行单个操作的显式局部变量与直接在获取值的方式上进行操作略有不同,尽管您的示例不是其中之一。