damoshayu.cn,苍井空浴缸大战猛男120分钟,网址你懂的,中国女人内射6XXXXXWWW

ref(refrain)

前沿拓展:

ref

可以用替換的方法一次性把出現(xiàn)的“#REF!”刪掉。

1、以excel2010版本為例,如下圖的數(shù)據(jù)里有幾個“#REF!”,現(xiàn)要把它們都刪掉;

2、第一按Ctrl+H鍵調(diào)出替換設(shè)置框,查找內(nèi)容填“#REF!”,替換為不填,空白,第二點(diǎn)擊左下角的“全部替換”;

3、在彈出的替換結(jié)果點(diǎn)擊下面的“確定”則可;

4、就會回到這個界面,直接點(diǎn)擊右下角的“關(guān)閉”則可亞按降言搞意房等超到覺

5、就會看到表中數(shù)據(jù)里硫屋源貴井醫(yī)縮子的“#REF!”都刪掉了。


一:背景1. 講故事

最近在翻 netcore 源碼看,發(fā)現(xiàn)框架中有不少的代碼都被 ref 給修飾了,我去,這還是我認(rèn)識的 ref 嗎?就拿 Span 來說,代碼如下:

public readonly ref struct Span<T>
{
public ref T GetPinnableReference()
{
ref T result = ref Unsafe.AsRef<T>(null);
if (_length != 0)
{
result = ref _pointer.Value;
}
return ref result;
}

public ref T this[int index]
{
get
{
return ref Unsafe.Add(ref _pointer.Value, index);
}
}
}

是不是到處都有 ref,在 struct 上有,在 local variable 也有,在 方法簽名處 也有,在 方法調(diào)用處 也有,在 屬性 上也有, 在 return處 也有,簡直是應(yīng)有盡有,太啦,那這一篇我們就來聊聊這個奇葩的 ref。

二:ref 各場景下的代碼解析1. 動機(jī)

不知道大家有沒有發(fā)現(xiàn),在 C# 7.0 之后,語言團(tuán)隊(duì)對性能這一塊真的是前所未有的重視,還專門為此出了各種類和底層支持,比如說 Span, Memory,ValueTask,還有本篇要介紹的ref。

在大家傳統(tǒng)的認(rèn)知中 ref 是用在方法參數(shù)上,用于給 值類型 做引用傳值,一個是為了大家業(yè)務(wù)上需要多次原地修改的情況,二個是為了避免值類型的copy引發(fā)的性能開銷,不知道是哪一位大神腦洞大開,將 ref 應(yīng)用在你所知道的代碼各處,最終目的都是盡可能的提升性能。

2. ref struct 分析

從小就被教育 值類型分配在棧上,引用類型是在堆上,這話也是有問題的,因?yàn)橹殿愋鸵部梢苑峙湓诙焉希热缦旅娲a的 Location。

public class Program
{
public static void Main(string[] args)
{
var person = new Person() { Name = "張三", Location = new Point() { X = 10, Y = 20 } };

Console.ReadLine();
}
}

public class Person
{
public string Name { get; set; }

public Point Location { get; set; } //分配在堆上
}

public struct Point
{
public int X { get; set; }
public int Y { get; set; }
}

其實(shí)這也是很多新手朋友學(xué)習(xí)值類型疑惑的地方,可以用 windbg 到托管堆找一下 Person 問問看,如下代碼:

0:000> !dumpheap -type Person
Address MT Size
0000010e368aadb8 00007ffaf50c2340 32

0:000> !do 0000010e368aadb8
Name: ConsoleApp2.Person
MethodTable: 00007ffaf50c2340
EEClass: 00007ffaf50bc5e8
Size: 32(0x20) bytes
File: E:net5ConsoleApp1ConsoleApp2binDebugnetcoreapp3.1ConsoleApp2.dll
Fields:
MT Field Offset Type VT Attr Value Name
00007ffaf5081e18 4000001 8 System.String 0 instance 0000010e368aad98 <Name>k__BackingField
00007ffaf50c22b0 4000002 10 ConsoleApp2.Point 1 instance 0000010e368aadc8 <Location>k__BackingField

0:000> dp 0000010e368aadc8
0000010e`368aadc8 00000014`0000000a 00000000`00000000

上面代碼最后一行 00000014`0000000a 中的 14 和 a 就是 y 和 x 的值,穩(wěn)穩(wěn)當(dāng)當(dāng)?shù)拇娣旁诙阎?,如果你還不信就看看 gc 0代堆的范圍。

0:000> !eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x0000010E368A1030
generation 1 starts at 0x0000010E368A1018
generation 2 starts at 0x0000010E368A1000
ephemeral segment allocation context: none
segment begin allocated size
0000010E368A0000 0000010E368A1000 0000010E368B55F8 0x145f8(83448)

從最后一行可看出,剛才的 0000010e368aadc8 確實(shí)是在 0 代堆 0x0000010E368A1030 – 0000010E368B55F8 的范圍內(nèi)。

接下來的問題就是能不能給 struct 做一個限制,就像泛型約束一樣,不準(zhǔn) struct 分配在堆上,有沒有辦法呢? 辦法就是加一個 ref 限定即可,如下圖:

ref(refrain)

從錯誤提示中可以看出,有意讓 struct 分配到堆上的**作都是嚴(yán)格禁止的,要想過編譯器只能將 class person 改成 ref struct person,也就是文章開頭 Span 和 this[int index] 這樣,動機(jī)可想而知,一切都是為了性能。

3. ref method 分析

給方法的參數(shù)傳引用地址,我想很多朋友都已經(jīng)輕車熟路了,比如下面這樣:

public static int GetNum(ref int i)
{
return i;
}

現(xiàn)在大家可以試著跳出思維定勢,既然可以往方法內(nèi)仍 引用地址 ,那能不能往方法外拋 引用地址 呢? 如果這也能實(shí)現(xiàn)就比較有意思了,我可以對**內(nèi)的某一些數(shù)據(jù)進(jìn)行引用地址返回,在方法外照樣可以修改這些返回值,畢竟傳來傳去都是引用地址,如下代碼所示:

public class Program
{
public static void Main(string[] args)
{
var nums = new int[3] { 10, 20, 30 };

ref int num = ref GetNum(nums);

num = 50;

Console.WriteLine(#34;nums= {string.Join(",",nums)}");

Console.ReadLine();
}

public static ref int GetNum(int[] nums)
{
return ref nums[2];
}
}
ref(refrain)

可以看到,數(shù)組的最后一個值已經(jīng)由 30 -> 50 了,有些朋友可能會比較驚訝,這到底是怎么玩的,不用想就是引用地址到處漂,不信的話,看看 IL 代碼咯。

.method public hidebysig static
int32& GetNums (
int32[] nums
) cil managed
{
// Method begins at RVA 0x209c
// Code size 13 (0xd)
.maxstack 2
.locals init (
[0] int32&
)

// {
IL_0000: nop
// return ref nums[2];
IL_0001: ldarg.0
IL_0002: ldc.i4.2
IL_0003: ldelema [System.Runtime]System.Int32
IL_0008: stloc.0
// (no C# code)
IL_0009: br.s IL_000b

IL_000b: ldloc.0
IL_000c: ret
} // end of method Program::GetNums

.method public hidebysig static
void Main (
string[] args
) cil managed
{
IL_0013: ldloc.0
IL_0014: call int32& ConsoleApp2.Program::GetNums(int32[])
IL_0019: stloc.1
IL_001a: ldloc.1
IL_001b: ldc.i4.s 50
IL_003e: pop
IL_003f: ret
} // end of method Program::Main

可以看到,到處都是 & 取值運(yùn)算符,更直觀一點(diǎn)的話用 windbg 看一下。

0:000> !clrstack -a
OS Thread Id: 0x7040 (0)
000000D4E777E760 00007FFAF1C5108F ConsoleApp2.Program.Main(System.String[]) [E:net5ConsoleApp1ConsoleApp2Program.cs @ 28]
PARAMETERS:
args (0x000000D4E777E7F0) = 0x00000218c9ae9e60
LOCALS:
0x000000D4E777E7C8 = 0x00000218c9aeadd8
0x000000D4E777E7C0 = 0x00000218c9aeadf0

0:000> dp 0x00000218c9aeadf0
00000218`c9aeadf0 00000000`00000032 00000000`00000000

上面代碼處的 0x00000218c9aeadf0 就是 num 的引用地址,繼續(xù)用 dp 看一下這個地址上的值為 16進(jìn)制的32,也就是十進(jìn)制的 50 哈。

三:小編綜合來說

總的來說,netcore 就是在當(dāng)初盛行的 云計(jì)算 和 虛擬化 時代誕生,基因和使命促使它必須要優(yōu)化優(yōu)化再優(yōu)化,再小的螞蟻也是肉,最后就是 C# **

更多高質(zhì)量干貨:參見我的 GitHub: dotnetfly**

拓展知識:

ref

ref 英[ref] 美[ref]
[詞典] (商業(yè)信函、文件的) 編號;
n. (足球、拳擊等比賽的) 主裁判;

化妝品外包裝上的REF為Reference的縮寫,為參考尺寸的意思。
藥品盒上REF:Reference 參考號,可以是商品號或合同號。

本回答被網(wǎng)友采納

ref

原創(chuàng)文章,作者:九賢生活小編,如若轉(zhuǎn)載,請注明出處:http:///39243.html