前沿拓展:
ref
一、第一,打開(kāi)Excel表格程序,進(jìn)入到程序主界面中,可以看到單元格中的“#REF!”出現(xiàn)問(wèn)題。
二、第二,選中出現(xiàn)“#REF”的單元格,可以看到是引用了表格2中數(shù)據(jù)所以出現(xiàn)問(wèn)題。
三、第二,在左下角將表格切換到表格2“sheet2”,
四、第二,在表格2中看到,A1單元格有問(wèn)題。
五、第二,選中A1單元格,發(fā)現(xiàn)錯(cuò)誤的公式。
六、第二,在函數(shù)欄修改A3單元格的數(shù)值。
七、最后,回到表格一,可以看到#REF消失,問(wèn)題解決。
自從 C# 7.3 放開(kāi) ref 之后,這玩法就太花哨了,也讓 C# 這門(mén)語(yǔ)言變得越來(lái)越多范式,越來(lái)越重,這篇我們就來(lái)聊聊 ref,本質(zhì)上來(lái)說(shuō) ref 的放開(kāi)就是把 C/C++ 指針的那一套又拿回來(lái)了,而且還封裝成一套自己的玩法,下面一一解讀下。
一:方法參數(shù)上的 ref
我想設(shè)計(jì)者的初心把 ref 的功能限制的****的,可能也考慮到 C# 是一門(mén)面向業(yè)務(wù)開(kāi)發(fā)的語(yǔ)言,講究的是做項(xiàng)目快狠準(zhǔn),性能反而不是第一要素,這個(gè)時(shí)候的 ref 很簡(jiǎn)單,看一下代碼:
class Program
{
static void Main(string[] args)
{
long price = 0;
GetPrice(ref price);
Console.WriteLine(#34;output: price={price}");
}
public static void GetPrice(ref long price)
{
price = 10;
}
}
output: price=10
我相信很有朋友都知道,方法參數(shù)中的 ref long price 拿的是棧地址,對(duì)棧地址上的值進(jìn)行修改,自然就修改了指向這些地址上的變量,和引用類型原理一致,接下來(lái)我們從匯編角度去驗(yàn)證,在 Price 方法上下一個(gè)斷點(diǎn)。
D:net5ConsoleApp4ConsoleApp3Program.cs @ 16:
026b048e 8d4dec lea ecx,[ebp-14h]
026b0491 ff15a0ebc800 call dword ptr ds:[0C8EBA0h] (ConsoleApp3.Program.GetPrice(Int64 ByRef), mdToken: 06000002)
026b0497 90 nop
0:000> bp 026b0491
0:000> g
Breakpoint 1 hit
ChangeEngineState
eax=00000000 ebx=0057f354 ecx=0057f2d4 edx=783aaa50 esi=02979e7c edi=0057f2dc
eip=026b0491 esp=0057f2c4 ebp=0057f2e8 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
026b0491 ff15a0ebc800 call dword ptr ds:[0C8EBA0h] ds:002b:00c8eba0=00c2be10
從匯編的 lea ecx,[ebp-14h] 就能看到,將 ebp-14 這個(gè)單元的內(nèi)存地址給了 ecx,這個(gè) ecx 也就是作為參數(shù)傳遞給了 Price 方法,后續(xù)的賦值將會(huì)影響這個(gè)棧位置 上的內(nèi)容。
2. 方法返回值上的 ref
這就有意思了,進(jìn)入的時(shí)候傳地址,回來(lái)的時(shí)候也想傳地址,很顯然方法線程棧上的 值類型 是傳不出去的,畢竟方法返回后,esp,ebp 所控制的方法棧幀空間是要銷毀的,所以只能是堆上對(duì)象才能實(shí)現(xiàn)。
為了方便理解,看如下代碼:
class Program
{
static void Main(string[] args)
{
ref long price = ref GetCurrentPrice();
price = 12;
Console.WriteLine(#34;output: price={price}");
}
public static ref long GetCurrentPrice()
{
long[] nums = { 10, 20, 30 };
return ref nums[1];
}
}
output: price=12
可以看到當(dāng)前的 price=12,同時(shí) nums 這個(gè)數(shù)組也被修改了,可以用 windbg 驗(yàn)證一下。
0:000> !dumpheap -type System.Int64[]
Address MT Size
027ca7b0 04c39d00 36
Statistics:
MT Count TotalSize Class Name
04c39d00 1 36 System.Int64[]
Total 1 objects
0:000> dq 027ca7b0 L4
027ca7b0 00000003`04c39d00 00000000`0000000a
027ca7c0 00000000`0000000c 00000000`0000001e
可以看到上面的 000000000000000c 被修改成 price=12 ,這時(shí)候有人就不爽了,我不希望外面的代碼能修改 price 內(nèi)容,那怎么辦呢? 還得在 ref 后面加上 readonly ,改造后如下:
到此時(shí)寫(xiě)法就有點(diǎn)瘋狂了,對(duì) C# 開(kāi)發(fā)者來(lái)說(shuō)很難理解,對(duì)熟悉 C/C++ 指針的朋友來(lái)說(shuō)又很不習(xí)慣,太糾結(jié)了,下面是一段翻譯過(guò)來(lái)的 C/C++指針代碼 。
const long long* getcurrentprice();
int main()
{
int i = 0;
const long long* price = getcurrentprice();
price = 12;
printf("num=%d, price=%d n", i, *price);
}
const long long* getcurrentprice() {
long long* num = new long long[3]{ 10,20,30 };
return num + 1;
}
說(shuō)實(shí)話,這代碼看起來(lái)就清爽多了。
2. 對(duì) ref 變量的 in **作
這又是一套 C/C++ 的玩法,有時(shí)候不希望某一個(gè)方法對(duì) ref 變量進(jìn)行修改,注意:是不希望某一個(gè)方法進(jìn)行修改,其他方法是可以的,那這個(gè)怎么實(shí)現(xiàn)呢?這就需要在入?yún)⑸霞?in 前綴,把代碼修改一下。
class Program
{
static void Main(string[] args)
{
ref long price = ref GetCurrentPrice();
ModifyPrice(in price);
Console.WriteLine(#34;output: price={price}");
}
public static ref long GetCurrentPrice()
{
long[] nums = { 10, 20, 30 };
return ref nums[1];
}
public static void ModifyPrice(in long price)
{
price = 12;
Console.WriteLine(price);
}
}
可以看到,這時(shí)候報(bào)錯(cuò)了,如果換成 C++ 就很簡(jiǎn)單了,只需要在參數(shù)上把 in 改成 const 即可。
void modifyprice(const long long* price) {
*price = 12;
printf("%d", *price);
}
文章來(lái)自https://www.cnblogs.com/huangxincheng/p/16188769.html
拓展知識(shí):
ref
ref是reference的縮寫(xiě),意思是“參照”,外貿(mào)函電中常見(jiàn)于Your ref No. or Our ref No.,其含義是你方來(lái)函編號(hào)(或我方)來(lái)函編號(hào),是函電格式的一部分,目的是為了告知對(duì)方本信是答復(fù)你方(或我方)前面的來(lái)函
本回答被網(wǎng)友采納
原創(chuàng)文章,作者:九賢生活小編,如若轉(zhuǎn)載,請(qǐng)注明出處:http://m.xiesong.cn/97403.html