2010-07-30 172 views
7

什麼(如果有的話)低於調用類的非靜態方法中的方式的上側或下側(性能,良好的編碼實踐中,無用單元收集等):調用一類的非靜態方法

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

對抗的

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

有什麼想法更「傳統」的方式,將不勝感激。

+0

ClassA是否創建任何非託管資源或實現IDisposable? – SwDevMan81 2010-07-30 14:15:44

回答

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。非常詳細的答案。正是我需要的。 – 2010-07-30 14:32:26

+0

此外,在@ SwDevMan81對此問題的評論中暗示 - 如果您使用的對象是一次性的,您希望將其放入一個變量中,以便稍後可以乾淨地處理它;這樣做的第一種方式是清理對象的終結器,這可能會(例如)使連接處於打開狀態。 – JohnLBevan 2013-08-28 10:07:50

3

它根本沒有任何區別。只是在這種情況下,靜態方法可能更合適。

+0

我同意,不幸的是,我的影響並沒有擴展到修改該類:)。也有點難以管理多線程 – 2010-07-30 14:18:22

0

一般來說,當我不需要類來「知道」任何東西時,我使用靜態方法;當類需要知道自己和自己的狀態時,我使用實例方法。

或多或少。

1

如果您不打算將ClassA用於其他任何事情,則不會使用new ClassA().MethodA(param1, param2);。否則,你應該走更傳統的例子ClassA classA = new ClassA();

+0

有道理。及時回覆非常感謝。 – 2010-07-30 14:24:32

0

我發現自己問你爲什麼要在呼叫站點這樣做。如果你無法繞過它,最好用靜態方法包裝new ClassA().MethodA(a,b)以避免呼叫站點的代碼噪聲。

+0

嗯......管理多線程變得棘手 – 2010-07-30 14:21:50

0

它們是相同的。第一種方法意味着少一行代碼。如果有人需要修改代碼以開始調用MethodB,則第二種方法稍好一些。

+0

對第二點有意義。無論如何,編譯器可能以同樣的方式解決問題。感謝您的快速響應 – 2010-07-30 14:23:52

1

我看不到他們之間的任何區別。但是,如果ClassA執行IDisposable這兩個都是一個壞主意。

+0

感謝您的快速響應。如果ClassA實現了IDisposable,那麼回聲是什麼? – 2010-07-30 14:22:40

+0

如果'ClassA'實現'IDisposable',則應該在不再需要實例時調用Dispose'方法,無論是手動還是通過'using'語句。如果不這樣做,可能會導致代碼泄漏非託管資源(具體取決於'ClassA'的作用)。 – 2010-07-30 14:25:21

+0

非常感謝Fredrik。我讚賞澄清。 – 2010-07-30 14:30:17

2

後端沒有區別。在CIL中它將創建一個ClassA對象,然後調用該方法。這兩段代碼都轉換爲相同的CIL,因此完全沒有性能差異。

+0

非常感謝斯科特,這就是我想知道的。 – 2010-07-30 14:28:42

1

兩者是相同的。實際上,編譯器會爲每個編譯器生成相同的IL。

傳統方法這是調試中的一個優點,如果您確定問題出在Ctor或MethodA中;或者如果MethodA更改對象,並且您需要檢查它。

+0

調試是一個很好的觀點。謝謝James – 2010-07-30 14:30:47

0

您的第一種方法需要實例化ClassA的一個實例(除了將類定義加載到內存中,如果該類從未被使用過)。第二種方法避免了這個額外的對象實例化和下面的類的垃圾回收。

如果這種情況偶爾發生,而不是數百萬次,我不會打擾。但是,如果您不需要訪問任何類實例方法或屬性,那麼實現靜態方法將是一個更乾淨的設計。

有時會使用稍微不同的方法:假設ClassA需要在其構造函數中有一個參數,它可能會初始化一個專用字段或屬性,這個屬性可能會被方法使用。在這種情況下,第一種方法是必須的:

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

但是 - 即使如此,該方法可以重新定義爲採取額外的參數。

相關問題