所以如果擴展方法和擴展屬性真的是靜態方法和屬性。靜態方法和屬性和方法不是線程安全的,因此應該避免使用擴展方法和擴展屬性。擴展方法和擴展屬性是不好的做法嗎?
我們只是被欺騙來做這些事情,因爲我們編寫的代碼會顯示爲漂亮或乾淨,但在性能方面並非如此。
這是真的嗎?
所以如果擴展方法和擴展屬性真的是靜態方法和屬性。靜態方法和屬性和方法不是線程安全的,因此應該避免使用擴展方法和擴展屬性。擴展方法和擴展屬性是不好的做法嗎?
我們只是被欺騙來做這些事情,因爲我們編寫的代碼會顯示爲漂亮或乾淨,但在性能方面並非如此。
這是真的嗎?
這取決於你如何寫擴展功能/屬性。如果他們不編輯或訪問共享狀態,即屬性和功能是清晰的功能:這絕對不是壞習慣。
實施例1:
fun String.countSpaces(): Int {
return this.count { c -> c == ' ' }
}
該功能完全在多線程環境中,由於String
是不可變的。
實施例2:
data class MutablePerson(val name: String, var speech: String)
fun MutablePerson.count(nextNumber: Int) {
this.speech = "${this.speech} ${nextNumber}"
}
此功能變異MutablePerson
對象的speech
屬性和分配操作不原子。如果count
將從不同線程的一個對象上調用 - 可能出現不一致的狀態。
例子:
fun main(args: Array<String>) {
val person = MutablePerson("Ruslan", "I'm starting count from 0 to 10:")
(1..10).forEach { it ->
Thread({
person.count(it)
println(person.speech)
}).start()
}
Thread.sleep(1000)
println(person.speech)
}
可能的輸出:
I'm starting count from 0 to 10: 1
I'm starting count from 0 to 10: 1 3
I'm starting count from 0 to 10: 1 3 4
I'm starting count from 0 to 10: 1 3 4 2
I'm starting count from 0 to 10: 1 3 4 2 5
I'm starting count from 0 to 10: 1 3 4 2 5 8
I'm starting count from 0 to 10: 1 3 4 2 5 6
I'm starting count from 0 to 10: 1 3 4 2 5 6 7
I'm starting count from 0 to 10: 1 3 4 2 5 6 7 9
I'm starting count from 0 to 10: 1 3 4 2 5 6 7 9 10
I'm starting count from 0 to 10: 1 3 4 2 5 6 7 9 10
所以擴展功能和擴展性也不錯的做法,他們就像在類的屬性和方法:這取決於你如何寫他們線程安全與否。
靜態方法與實例方法一樣擁有自己的堆棧。因此,靜態方法中的臨時變量就像實例方法一樣在棧上。交給靜態方法的參數在訪問共享狀態時可能會遇到線程問題,但這與實例方法的情況完全相同。
想象Java中帶有靜態方法的大量的Util類作爲Java沒有擴展函數的解決方法。在多線程方面沒有什麼問題。
在C#擴展方法也在現場靜態方法後面,它不會做任何傷害,看到How extension methods are implemented internally
正如你所說,擴展函數,靜態解決。所以如果你開始使用擴展功能作爲創建實用程序類的方法,那麼這是一個不好的做法。
在Java中,Utils類通常是一種不好的做法,不僅是因爲線程安全,而且因爲它們可能是惡劣設計的代碼味道,因爲它們很難測試。
靜態方法的主要問題是它們不能被嘲笑(至少與Mockito一起),所以你會提出無法測試你的代碼。
但是,如果你使用的擴展功能,對於有沒有必要進行再測試,這根本不是一個不好的做法小型的,孤立的任務(如幫手敬酒,日誌...)
沒有,聲明「靜態方法不是線程安全的「是不正確的(並且它都是錯誤的)。 – Ilya