本文敘述的問題的根源在於對C#基礎知識掌握不牢固,從而在遇到難以理解的問題時浪費了大量時間; 在此也警示自己,該啃啃基礎書籍了! 話不多說,先上代碼: 先看問題 services.AddEasyCaching(option => { option.UseHybrid(config => { .... ...
本文敘述的問題的根源在於對C#基礎知識掌握不牢固,從而在遇到難以理解的問題時浪費了大量時間;
在此也警示自己,該啃啃基礎書籍了!
話不多說,先上代碼:
先看問題
services.AddEasyCaching(option =>
{
option.UseHybrid(config =>
{
.....
})
.WithZookeeeperBus(busConf =>
{
// 方式1
busConf.ConnectionString = "192.168.3.86:2181";
// 方式2
busConf = new ZkBusOptions
{
ConnectionString = "192.168.3.86:2181",
};
});
});
這是我在使用EasyCaching
時的一段註冊代碼,在配置Zookeeeper Bus
時調用了WithZookeeeperBus(Action<ZkBusOptions>)
拓展方法,並採用瞭如上兩種賦值方式,看似都能正常配置,但實際不盡人意:
方式1:配置正常;
方式2:配置無效,最終ConnectionString=null
;
what?肯定是編譯器問題!( 確信
此時我的心情極其複雜,這兩種賦值不是一樣的?
問題在哪?
一開始,我甚至懷疑是自己對Action<T>
的理解不到位,存在某種機制導致的問題,但事實證明,飯可以亂吃,鍋不能亂甩;
每每想起這,不由得老臉一紅!
問題在這
實則問題是在最基礎的方法傳參問題;
咱們可以先理解一下方法傳參存在哪幾種情況,以及情況對應傳參方式;
在C#參數傳遞分為如下四種:
- 值類型的值傳遞(將值類型的副本傳遞給方法)
- 值類型的引用傳遞(將值類型本身傳遞給方法,例如:使用了
ref int a
)- 引用類型的值傳遞(將引用的副本傳遞給方法 )
- 引用類型的引用傳遞(將引用本身傳遞給方法,例如:使用了
ref object o
)
此時,如果你已經悟了,那文章到此結束,還一知半解的,請繼續往下看;
再細一點
先看看如下代碼:
void Main()
{
var p = new Person { Name = "jason", Age = 19 };
// 賦值方法 1
AssignmentPerson_1(p);
Console.WriteLine($"Name: {p.Name}; Age: {p.Age}");
// 賦值方法 2
AssignmentPerson_2(p);
Console.WriteLine($"Name: {p.Name}; Age: {p.Age}");
}
public void AssignmentPerson_1(Person t)
{
var np = new Person { Name = "jack", Age = 18 };
t = np;
}
public void AssignmentPerson_2(Person t)
{
var np zhanzhi
很顯然,在本文起始的教訓下,答案是明顯,會輸出如下:
Name = "jason"; Age = 19
Name = "jack"; Age = 18
首先,在main中創建了p
,假設p
在棧中的地址為0x0001
,棧值為指向堆中實例的地址0x00D1
;
賦值方法-1
然後,開始調用AssignmentPerson_1(Person t)
,並傳入p
;
此時,不是直接將 p
(棧地址:0x0001
)傳入方法,而是拷貝了一份p
(棧地址:0x0005
),並且同時將棧值賦為0x00D1
,傳入方法中;
所以,AssignmentPerson_1(Person t)
中t
的地址為0x0005
;
最後,新建np
,棧地址為0x000A
,棧值為指向堆中實例的地址0x00D5
;
並將t = np
,t
的棧值被替換了0x00D1
-> 0x00D5
;
最終,p
的棧值還是0x00D1
,並且0x00D1
中的堆值也並未發生變化,所以賦值無效;
賦值方法-2
同理,當調用AssignmentPerson_2(Person t)
時,同樣傳入p
,同樣新建np
;
但是,並沒有替換t
的棧值,它仍舊與p
指向的堆地址相同,為0x00D1
;
此時賦值操作只是替換了堆值中實例的屬性值:t.Name = np.Name
,t.Age = np.Age
;
所以,t
指向的堆值發生了變化, t
與p
又指向地址相同,p
的實例屬性值也就發生了變化;
總結
該讀一本《CLR via》了!
參考
1-關於C#函數對象參數傳遞的問題
2-徹底澄清:C#方法參數