调用类的非静态方法

7

在下面的方式中调用类的非静态方法的优缺点是什么(性能、良好的编码实践、垃圾回收等)(如果有的话):

new ClassA().MethodA(param1, param2);

相较于更“传统”的方式

ClassA classA = new ClassA();
classA.MethodA(param1, param2);

非常感谢您的意见。


ClassA 是否创建任何非托管资源或实现 IDisposable 接口? - SwDevMan81
10个回答

10

编程
至于编码练习,第二种选项更好,即首先将对象存储在变量中。使其更好的原因是您可以根据使用它的上下文来命名对象。举个例子:

var pendingUserForRegistration = new User();

性能
就性能而言,第一种选项可能会稍微好一些,因为它直接从堆栈中使用对象,跳过在本地变量中存储对象的步骤。可以从方法的IL代码中看到:

第一种选项的IL代码:

.maxstack 8
L_0000: nop 
L_0001: newobj instance void NS.ClassA::.ctor()
L_0006: call instance void MS.ClassA::M()
L_000b: nop 
L_000c: ret 

第二层IL:

.maxstack 1
.locals init (
    [0] class NS.ClassA c)
L_0000: nop 
L_0001: newobj instance void NS.ClassA::.ctor()
L_0006: stloc.0 
L_0007: ldloc.0 
L_0008: callvirt instance void NS.ClassA::M()
L_000d: nop 
L_000e: ret 

通常情况下,这只会带来微小的性能开销,很难找到一个真正需要解决性能问题的案例。


底线
由于代码的可维护性优势大于性能优势,因此最好将对象存储在具有有意义名称的变量中。


1
谢谢Elisha。非常详细的回答,正是我所需要的。 - Rishi Bhatnagar
此外,在@SwDevMan81对问题的评论中提到 - 如果您正在使用的对象是可处理的,则应将其放入变量中,以便稍后可以清理它;以第一种方式执行会将清理工作留给对象的终结器,这可能会导致连接保持打开状态。 - JohnLBevan

3

这并不会有任何区别。只是在这种情况下,静态方法可能更适合。


我同意,不幸的是我的影响力无法扩展到修改那个类 :). 同时,多线程管理也变得有点困难。 - Rishi Bhatnagar

2

在后端没有区别。在CIL中,它将创建一个ClassA对象,然后调用方法。这两段代码都翻译成相同的CIL,因此完全没有性能差异。


1
如果您不打算在其他地方使用ClassA,那么new ClassA().MethodA(param1, param2);就可以了。否则,您应该选择更传统的实例化方式ClassA classA = new ClassA();

有道理。非常感谢你的快速回复。 - Rishi Bhatnagar

1

我看不出它们之间有任何区别。但是,如果ClassA实现了IDisposable接口,那么两者都是不好的选择。


感谢您的快速回复。如果ClassA实现IDisposable接口,会有什么后果? - Rishi Bhatnagar
如果ClassA实现了IDisposable接口,当实例不再需要时,应手动或通过using语句调用Dispose方法。未这样做可能会导致代码泄漏非托管资源(取决于ClassA的操作)。 - Fredrik Mörk
非常感谢你,Fredrik。我很感激你的澄清。 - Rishi Bhatnagar

1

这两者是完全相同的。实际上,编译器很有可能为它们生成相同的IL代码。

传统方法在调试方面具有优势,如果您确定问题是出现在构造函数还是MethodA中;或者如果MethodA修改了对象并且您需要检查它,则可以使用传统方法。


0
通常情况下,当我不需要类“知道”任何东西时,我使用静态方法;当类需要意识到自身及其自身状态时,我使用实例方法。
或多或少。

0
我发现自己在问为什么你想在调用站点这样做。如果你无法避免它,最好将 new ClassA().MethodA(a,b) 包装在一个静态方法中,以避免在调用站点产生代码噪音。

0

它们是相同的。第一种方法意味着少了一行代码。如果有人需要修改代码以开始调用MethodB,则第二种方法稍微好一些。


第二点说得有道理。也许编译器无论如何都会解决这两个问题。感谢您如此迅速的回复。 - Rishi Bhatnagar

0

你的第一种方法需要实例化ClassA类的一个实例(如果该类从未被使用过,则还需要将类定义加载到内存中)。第二种方法避免了这种额外的对象实例化和随后的垃圾回收。

如果这种情况偶尔发生而不是数百万次,我就不会担心。然而,如果您不需要访问任何类实例方法或属性,则实现静态方法将是更清晰的设计。

有时候会使用稍微不同的方法:假设ClassA在其构造函数中需要一个参数,该参数可能会初始化一个私有字段或属性,而该字段或属性又会被您的方法使用。在这种情况下,第一种方法是必须的:

new ClassA(param0).MethodA(param1, param2);

但是 - 即使如此,该方法也可以重新定义以接受其他参数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接