欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C#使用位域技術(shù)進(jìn)行對(duì)象二進(jìn)制序列化優(yōu)

 更新時(shí)間:2024年01月23日 08:38:15   作者:Dotnet9個(gè)人博客  
在操作系統(tǒng)中,進(jìn)程信息對(duì)于系統(tǒng)監(jiān)控和性能分析至關(guān)重要,這個(gè)過(guò)程中,如何將捕獲到的進(jìn)程對(duì)象轉(zhuǎn)換為二進(jìn)制數(shù)據(jù),并進(jìn)行優(yōu)化,以減小數(shù)據(jù)包的大小,成為了一個(gè)關(guān)鍵問(wèn)題,下面我們就來(lái)看看如何使用位域技術(shù)對(duì)C#對(duì)象進(jìn)行二進(jìn)制序列化優(yōu)化吧

1. 引言

在操作系統(tǒng)中,進(jìn)程信息對(duì)于系統(tǒng)監(jiān)控和性能分析至關(guān)重要。假設(shè)我們需要開(kāi)發(fā)一個(gè)監(jiān)控程序,該程序能夠捕獲當(dāng)前操作系統(tǒng)的進(jìn)程信息,并將其高效地傳輸?shù)狡渌耍ㄈ绶?wù)端或監(jiān)控端)。在這個(gè)過(guò)程中,如何將捕獲到的進(jìn)程對(duì)象轉(zhuǎn)換為二進(jìn)制數(shù)據(jù),并進(jìn)行優(yōu)化,以減小數(shù)據(jù)包的大小,成為了一個(gè)關(guān)鍵問(wèn)題。本文將通過(guò)逐步分析,探討如何使用位域技術(shù)對(duì)C#對(duì)象進(jìn)行二進(jìn)制序列化優(yōu)化。

首先,我們給出了一個(gè)進(jìn)程對(duì)象的字段定義示例。為了通過(guò)網(wǎng)絡(luò)(TCP/UDP)傳輸該對(duì)象,我們需要將其轉(zhuǎn)換為二進(jìn)制格式。在這個(gè)過(guò)程中,如何做到最小的數(shù)據(jù)包大小是一個(gè)挑戰(zhàn)。

字段名說(shuō)明示例
PID進(jìn)程ID10565
Name進(jìn)程名稱(chēng)碼界工坊
Publisher發(fā)布者沙漠盡頭的狼
CommandLine命令行dotnet CodeWF.Tools.dll
CPUCPU(所有內(nèi)核的總處理利用率)2.3%
Memory內(nèi)存(進(jìn)程占用的物理內(nèi)存)0.1%
Disk磁盤(pán)(所有物理驅(qū)動(dòng)器的總利用率)0.1 MB/秒
Network網(wǎng)絡(luò)(當(dāng)前主要網(wǎng)絡(luò)上的網(wǎng)絡(luò)利用率0 Mbps
GPUGPU(所有GPU引擎的最高利用率)2.2%
GPUEngineGPU引擎GPU 0 - 3D
PowerUsage電源使用情況(CPU、磁盤(pán)和GPU對(duì)功耗的影響)
PowerUsageTrend電源使用情況趨勢(shì)(一段時(shí)間內(nèi)CPU、磁盤(pán)和GPU對(duì)功耗的影響)非常低
Type進(jìn)程類(lèi)型應(yīng)用
Status進(jìn)程狀態(tài)效率模式

2. 優(yōu)化過(guò)程

2.1. 進(jìn)程對(duì)象定義與初步分析

我們根據(jù)字段的示例值確定了每個(gè)字段的數(shù)據(jù)類(lèi)型。

字段名數(shù)據(jù)類(lèi)型說(shuō)明示例
PIDint進(jìn)程ID10565
Namestring?進(jìn)程名稱(chēng)碼界工坊
Publisherstring?發(fā)布者沙漠盡頭的狼
CommandLinestring?命令行dotnet CodeWF.Tools.dll
CPUstring?CPU(所有內(nèi)核的總處理利用率)2.3%
Memorystring?內(nèi)存(進(jìn)程占用的物理內(nèi)存)0.1%
Diskstring?磁盤(pán)(所有物理驅(qū)動(dòng)器的總利用率)0.1 MB/秒
Networkstring?網(wǎng)絡(luò)(當(dāng)前主要網(wǎng)絡(luò)上的網(wǎng)絡(luò)利用率0 Mbps
GPUstring?GPU(所有GPU引擎的最高利用率)2.2%
GPUEnginestring?GPU引擎GPU 0 - 3D
PowerUsagestring?電源使用情況(CPU、磁盤(pán)和GPU對(duì)功耗的影響)
PowerUsageTrendstring?電源使用情況趨勢(shì)(一段時(shí)間內(nèi)CPU、磁盤(pán)和GPU對(duì)功耗的影響)非常低
Typestring?進(jìn)程類(lèi)型應(yīng)用
Statusstring?進(jìn)程狀態(tài)效率模式

創(chuàng)建一個(gè)C#類(lèi)SystemProcess表示進(jìn)程信息:

public class SystemProcess
{
    public int PID { get; set; }
    public string? Name { get; set; }
    public string? Publisher { get; set; }
    public string? CommandLine { get; set; }
    public string? CPU { get; set; }
    public string? Memory { get; set; }
    public string? Disk { get; set; }
    public string? Network { get; set; }
    public string? GPU { get; set; }
    public string? GPUEngine { get; set; }
    public string? PowerUsage { get; set; }
    public string? PowerUsageTrend { get; set; }
    public string? Type { get; set; }
    public string? Status { get; set; }
}

定義測(cè)試數(shù)據(jù)

private SystemProcess _codeWFObject = new SystemProcess()
{
    PID = 10565,
    Name = "碼界工坊",
    Publisher = "沙漠盡頭的狼",
    CommandLine = "dotnet CodeWF.Tools.dll",
    CPU = "2.3%",
    Memory = "0.1%",
    Disk = "0.1 MB/秒",
    Network = "0 Mbps",
    GPU = "2.2%",
    GPUEngine = "GPU 0 - 3D",
    PowerUsage = "低",
    PowerUsageTrend = "非常低",
    Type = "應(yīng)用",
    Status = "效率模式"
};

2.2. 排除Json序列化

將對(duì)象轉(zhuǎn)為Json字段串,這在Web開(kāi)發(fā)是最常見(jiàn)的,因?yàn)楹?jiǎn)潔,前后端都方便處理:

public class SysteProcessUnitTest
{
    private readonly ITestOutputHelper _testOutputHelper;

    private SystemProcess _codeWFObject // 前面已給出定義,這里省

    public SysteProcessUnitTest(ITestOutputHelper testOutputHelper)
    {
        _testOutputHelper = testOutputHelper;
    }

    /// <summary>
    /// Json序列化大小測(cè)試
    /// </summary>
    [Fact]
    public void Test_SerializeJsonData_Success()
    {
        var jsonData = JsonSerializer.Serialize(_codeWFObject);
        _testOutputHelper.WriteLine($"Json長(zhǎng)度:{jsonData.Length}");

        var jsonDataBytes = Encoding.UTF8.GetBytes(jsonData);
        _testOutputHelper.WriteLine($"json二進(jìn)制長(zhǎng)度:{jsonDataBytes.Length}");
    }
}

標(biāo)準(zhǔn)輸出: 

Json長(zhǎng)度:366
json二進(jìn)制長(zhǎng)度:366

盡管Json序列化在Web開(kāi)發(fā)中非常流行,因?yàn)樗?jiǎn)潔且易于處理,但在TCP/UDP網(wǎng)絡(luò)傳輸中,Json序列化會(huì)導(dǎo)致不必要的數(shù)據(jù)包大小增加(冗余的字段名聲明)。因此,我們排除了Json序列化,并尋找其他更高效的二進(jìn)制序列化方法。

{"PID":10565,"Name":"\u7801\u754C\u5DE5\u574A","Publisher":"\u6C99\u6F20\u5C3D\u5934\u7684\u72FC","CommandLine":"dotnet CodeWF.Tools.dll","CPU":"2.3%","Memory":"0.1%","Disk":"0.1 MB/\u79D2","Network":"0 Mbps","GPU":"2.2%","GPUEngine":"GPU 0 - 3D","PowerUsage":"\u4F4E","PowerUsageTrend":"\u975E\u5E38\u4F4E","Type":"\u5E94\u7528","Status":"\u6548\u7387\u6A21\u5F0F"}

2.3. 使用BinaryWriter進(jìn)行二進(jìn)制序列化

使用站長(zhǎng)前面一篇文章寫(xiě)的二進(jìn)制序列化幫助類(lèi)SerializeHelper轉(zhuǎn)換,該類(lèi)使用BinaryWriter將對(duì)象轉(zhuǎn)換為二進(jìn)制數(shù)據(jù)(反序列化使用BinaryReader)。

首先,我們使SystemProcess類(lèi)實(shí)現(xiàn)了一個(gè)空接口INetObject,并在類(lèi)上添加了NetHeadAttribute特性(加上了數(shù)據(jù)包頭部定義,便于多個(gè)網(wǎng)絡(luò)對(duì)象反序列化識(shí)別,序列化后會(huì)多出數(shù)個(gè)字節(jié),主要是系統(tǒng)Id、網(wǎng)絡(luò)對(duì)象Id、對(duì)象版本號(hào)等序列化輔助字段)。

/// <summary>
/// 網(wǎng)絡(luò)對(duì)象序列化接口
/// </summary>
public interface INetObject
{
}
[NetHead(1, 1)]
public class SystemProcess : INetObject
{
  // 省略字段定義   
}

然后,我們編寫(xiě)了一個(gè)單元測(cè)試方法來(lái)驗(yàn)證序列化和反序列化的正確性,并打印了序列化后的二進(jìn)制數(shù)據(jù)長(zhǎng)度。

/// <summary>
/// 二進(jìn)制序列化測(cè)試
/// </summary>
[Fact]
public void Test_SerializeToBytes_Success()
{
    var buffer = SerializeHelper.SerializeByNative(_codeWFObject, 1);
    _testOutputHelper.WriteLine($"序列化后二進(jìn)制長(zhǎng)度:{buffer.Length}");

    var deserializeObj = SerializeHelper.DeserializeByNative<SystemProcess>(buffer);
    Assert.Equal("碼界工坊", deserializeObj.Name);
}

標(biāo)準(zhǔn)輸出: 

序列化后二進(jìn)制長(zhǎng)度:152

比Json體積小了一半以上(366到152,還多了幾個(gè)字段哦),上面單元測(cè)試也測(cè)試了數(shù)據(jù)反序列化后驗(yàn)證數(shù)據(jù)是否正確,我們就以這個(gè)基礎(chǔ)繼續(xù)優(yōu)化。

2.4. 數(shù)據(jù)類(lèi)型調(diào)整

為了進(jìn)一步優(yōu)化二進(jìn)制數(shù)據(jù)的大小,我們對(duì)數(shù)據(jù)類(lèi)型進(jìn)行了調(diào)整。通過(guò)對(duì)進(jìn)程數(shù)據(jù)示例的分析,我們發(fā)現(xiàn)一些字段的數(shù)據(jù)類(lèi)型可以更加緊湊地表示。例如,CPU利用率可以只傳遞數(shù)字部分(如2.3),而不需要傳遞百分號(hào);進(jìn)程類(lèi)型只傳遞枚舉值,而不用傳遞個(gè)性化字符串。這種調(diào)整可以減小數(shù)據(jù)包的大小。

字段名數(shù)據(jù)類(lèi)型說(shuō)明示例
PIDint進(jìn)程ID10565
Namestring?進(jìn)程名稱(chēng)碼界工坊
Publisherstring?發(fā)布者沙漠盡頭的狼
CommandLinestring?命令行dotnet CodeWF.Tools.dll
CPUfloatCPU(所有內(nèi)核的總處理利用率)2.3
Memoryfloat內(nèi)存(進(jìn)程占用的物理內(nèi)存)0.1
Diskfloat磁盤(pán)(所有物理驅(qū)動(dòng)器的總利用率)0.1
Networkfloat網(wǎng)絡(luò)(當(dāng)前主要網(wǎng)絡(luò)上的網(wǎng)絡(luò)利用率0
GPUfloatGPU(所有GPU引擎的最高利用率)2.2
GPUEnginebyteGPU引擎,0:無(wú),1:GPU 0 - 3D1
PowerUsagebyte電源使用情況(CPU、磁盤(pán)和GPU對(duì)功耗的影響),0:非常低,1:低,2:中,3:高,4:非常高1
PowerUsageTrendbyte電源使用情況趨勢(shì)(一段時(shí)間內(nèi)CPU、磁盤(pán)和GPU對(duì)功耗的影響),0:非常低,1:低,2:中,3:高,4:非常高0
Typebyte進(jìn)程類(lèi)型,0:應(yīng)用,1:后臺(tái)進(jìn)程0
Statusbyte進(jìn)程狀態(tài),0:正常運(yùn)行,1:效率模式,2:掛起1

修改測(cè)試數(shù)據(jù)定義:

[NetHead(1, 2)]
public class SystemProcess2 : INetObject
{
    public int PID { get; set; }
    public string? Name { get; set; }
    public string? Publisher { get; set; }
    public string? CommandLine { get; set; }
    public float CPU { get; set; }
    public float Memory { get; set; }
    public float Disk { get; set; }
    public float Network { get; set; }
    public float GPU { get; set; }
    public byte GPUEngine { get; set; }
    public byte PowerUsage { get; set; }
    public byte PowerUsageTrend { get; set; }
    public byte Type { get; set; }
    public byte Status { get; set; }
}
/// <summary>
/// 普通優(yōu)化字段數(shù)據(jù)類(lèi)型
/// </summary>
private SystemProcess2 _codeWFObject2 = new SystemProcess2()
{
    PID = 10565,
    Name = "碼界工坊",
    Publisher = "沙漠盡頭的狼",
    CommandLine = "dotnet CodeWF.Tools.dll",
    CPU = 2.3f,
    Memory = 0.1f,
    Disk = 0.1f,
    Network = 0,
    GPU = 2.2f,
    GPUEngine = 1,
    PowerUsage = 1,
    PowerUsageTrend = 0,
    Type = 0,
    Status = 1
};

添加單元測(cè)試如下:

/// <summary>
/// 二進(jìn)制序列化測(cè)試
/// </summary>
[Fact]
public void Test_SerializeToBytes2_Success()
{
    var buffer = SerializeHelper.SerializeByNative(_codeWFObject2, 1);
    _testOutputHelper.WriteLine($"序列化后二進(jìn)制長(zhǎng)度:{buffer.Length}");

    var deserializeObj = SerializeHelper.DeserializeByNative<SystemProcess2>(buffer);
    Assert.Equal("碼界工坊", deserializeObj.Name);
    Assert.Equal(2.2f, deserializeObj.GPU);
}

測(cè)試結(jié)果:

標(biāo)準(zhǔn)輸出: 
序列化后二進(jìn)制長(zhǎng)度:99

包體積又優(yōu)化了1/3,由152字節(jié)減小到99字節(jié)長(zhǎng)度,這是部分字段string?調(diào)整為float或byte的結(jié)果。

2.5. 再次數(shù)據(jù)類(lèi)型調(diào)整與位域優(yōu)化

更進(jìn)一步地,我們引入了位域技術(shù)。位域允許我們更加精細(xì)地控制字段在內(nèi)存中的布局,從而進(jìn)一步減小二進(jìn)制數(shù)據(jù)的大小。我們重新定義了字段規(guī)則,并使用位域來(lái)表示一些枚舉值字段。通過(guò)這種方式,我們能夠顯著地減小數(shù)據(jù)包的大小。

看前面一張表和下表比對(duì),主要是兩種數(shù)據(jù)類(lèi)型調(diào)整,規(guī)則如下:

第一種:部分字段只是一些枚舉值,使用的byte表示,即8位(bit),其中比如進(jìn)程類(lèi)型只有2個(gè)狀態(tài)(0:應(yīng)用,1:后臺(tái)進(jìn)程),正好可以用1位表示(0、1);像電源使用情況,無(wú)非就是5個(gè)狀態(tài),用3位可表示全(可表示6種狀態(tài));

第二種:部分float數(shù)據(jù)類(lèi)型,實(shí)際情況我們只會(huì)要求精確到小數(shù)位1位。數(shù)值表示的百分比,那么不會(huì)超過(guò)1(即100.0%),可以考慮取整,如23.3%,傳遞的23.3,乘以10,傳233即可,最大不會(huì)超過(guò)1000(即100.0,100%),另一進(jìn)程解析數(shù)據(jù)后,再除以10使用,那么就可以將數(shù)據(jù)類(lèi)型由float表示的4字節(jié)32位優(yōu)化為10位(最大值1024)。

按這個(gè)規(guī)則我們重新定義字段規(guī)則如下:

字段名數(shù)據(jù)類(lèi)型說(shuō)明示例
PIDint進(jìn)程ID10565
Namestring?進(jìn)程名稱(chēng)碼界工坊
Publisherstring?發(fā)布者沙漠盡頭的狼
CommandLinestring?命令行dotnet CodeWF.Tools.dll
Databyte[8]固定大小的幾個(gè)字段,為啥是8個(gè)字節(jié)長(zhǎng)度(注:反序列化還會(huì)多定義4個(gè)字節(jié)表示byte[]長(zhǎng)度)?見(jiàn)下表定義

固定字段(Data)的詳細(xì)說(shuō)明如下:

字段名OffsetSize說(shuō)明示例
CPU010CPU(所有內(nèi)核的總處理利用率),最后一位表示小數(shù)位,比如23表示2.3%23
Memory1010內(nèi)存(進(jìn)程占用的物理內(nèi)存),最后一位表示小數(shù)位,比如1表示0.1%,值可根據(jù)基本信息計(jì)算1
Disk2010磁盤(pán)(所有物理驅(qū)動(dòng)器的總利用率),最后一位表示小數(shù)位,比如1表示0.1%,值可根據(jù)基本信息計(jì)算1
Network3010網(wǎng)絡(luò)(當(dāng)前主要網(wǎng)絡(luò)上的網(wǎng)絡(luò)利用率),最后一位表示小數(shù)位,比如253表示25.3%,值可根據(jù)基本信息計(jì)算0
GPU4010GPU(所有GPU引擎的最高利用率),最后一位表示小數(shù)位,比如253表示25.322
GPUEngine501GPU引擎,0:無(wú),1:GPU 0 - 3D1
PowerUsage513電源使用情況(CPU、磁盤(pán)和GPU對(duì)功耗的影響),0:非常低,1:低,2:中,3:高,4:非常高1
PowerUsageTrend543電源使用情況趨勢(shì)(一段時(shí)間內(nèi)CPU、磁盤(pán)和GPU對(duì)功耗的影響),0:非常低,1:低,2:中,3:高,4:非常高0
Type571進(jìn)程類(lèi)型,0:應(yīng)用,1:后臺(tái)進(jìn)程0
Status582進(jìn)程狀態(tài),0:正常運(yùn)行,1:效率模式,2:掛起1

上面這張表是部分固定示例字段的位域規(guī)則表,Offset表示字段在Data字節(jié)數(shù)組中的位置(以bit為單位計(jì)算),Size表示字段在Data中占有的大?。ㄍ瑯右詁it單位計(jì)算),如Memory字段,在Data字節(jié)數(shù)組中,占據(jù)10到20位的空間。

由此就將固定大小的、原本25個(gè)字節(jié)長(zhǎng)度的10個(gè)字段優(yōu)化到8字節(jié)了(5個(gè)float 4字節(jié)32位優(yōu)化為10位,單字節(jié)8位優(yōu)化到2位、4位、6位,即200位(25*8)優(yōu)化到64位(實(shí)際是60位,由于網(wǎng)絡(luò)傳輸最小單位是byte,所以向上取整8字節(jié)64位))。

修改類(lèi)定義如下,注意看代碼中的注釋?zhuān)?/p>

[NetHead(1, 3)]
public class SystemProcess3 : INetObject
{
    public int PID { get; set; }
    public string? Name { get; set; }
    public string? Publisher { get; set; }
    public string? CommandLine { get; set; }
    private byte[]? _data;
    /// <summary>
    /// 序列化,這是實(shí)際需要序列化的數(shù)據(jù)
    /// </summary>
    public byte[]? Data
    {
        get => _data;
        set
        {
            _data = value;

            // 這是關(guān)鍵:在反序列化將byte轉(zhuǎn)換為對(duì)象,方便程序中使用(位域操作)
            _processData = _data?.ToFieldObject<SystemProcessData>();
        }
    }

    private SystemProcessData? _processData;

    /// <summary>
    /// 進(jìn)程數(shù)據(jù),添加NetIgnoreMember在序列化會(huì)忽略
    /// </summary>
    [NetIgnoreMember]
    public SystemProcessData? ProcessData
    {
        get => _processData;
        set
        {
            _processData = value;

            // 這里關(guān)鍵:將對(duì)象轉(zhuǎn)換為byte[](位域序列化操作)
            _data = _processData?.FieldObjectBuffer();
        }
    }
}

public record SystemProcessData
{
    [NetFieldOffset(0, 10)] public short CPU { get; set; }
    [NetFieldOffset(10, 10)] public short Memory { get; set; }
    [NetFieldOffset(20, 10)] public short Disk { get; set; }
    [NetFieldOffset(30, 10)] public short Network { get; set; }
    [NetFieldOffset(40, 10)] public short GPU { get; set; }
    [NetFieldOffset(50, 1)] public byte GPUEngine { get; set; }
    [NetFieldOffset(51, 3)] public byte PowerUsage { get; set; }
    [NetFieldOffset(54, 3)] public byte PowerUsageTrend { get; set; }
    [NetFieldOffset(57, 1)] public byte Type { get; set; }
    [NetFieldOffset(58, 2)] public byte Status { get; set; }
}

添加單元測(cè)試如下:

/// <summary>
/// 極限優(yōu)化字段數(shù)據(jù)類(lèi)型
/// </summary>
private SystemProcess3 _codeWFObject3 = new SystemProcess3()
{
    PID = 10565,
    Name = "碼界工坊",
    Publisher = "沙漠盡頭的狼",
    CommandLine = "dotnet CodeWF.Tools.dll",
    ProcessData = new SystemProcessData()
    {
        CPU = 23,
        Memory = 1,
        Disk = 1,
        Network = 0,
        GPU = 22,
        GPUEngine = 1,
        PowerUsage = 1,
        PowerUsageTrend = 0,
        Type = 0,
        Status = 1
    }
};

/// <summary>
/// 二進(jìn)制極限序列化測(cè)試
/// </summary>
[Fact]
public void Test_SerializeToBytes3_Success()
{
    var buffer = SerializeHelper.SerializeByNative(_codeWFObject3, 1);
    _testOutputHelper.WriteLine($"序列化后二進(jìn)制長(zhǎng)度:{buffer.Length}");

    var deserializeObj = SerializeHelper.DeserializeByNative<SystemProcess3>(buffer);
    Assert.Equal("碼界工坊", deserializeObj.Name);
    Assert.Equal(23, deserializeObj.ProcessData.CPU);
    Assert.Equal(1, deserializeObj.ProcessData.PowerUsage);
}

測(cè)試輸出:

標(biāo)準(zhǔn)輸出: 
序列化后二進(jìn)制長(zhǎng)度:86

99又優(yōu)化到86個(gè)字節(jié),13個(gè)字節(jié)哦,有極限網(wǎng)絡(luò)環(huán)境下非??捎^,比如100萬(wàn)數(shù)據(jù),那不就是12.4MB了?關(guān)于位域序列化和反序列的代碼這里不細(xì)說(shuō)了,很枯燥,站長(zhǎng)可能也說(shuō)不清楚,代碼長(zhǎng)這樣:

public partial class SerializeHelper
{
    public static byte[] FieldObjectBuffer<T>(this T obj) where T : class
    {
        var properties = typeof(T).GetProperties();
        var totalSize = 0;

        // 計(jì)算總的bit長(zhǎng)度
        foreach (var property in properties)
        {
            if (!Attribute.IsDefined(property, typeof(NetFieldOffsetAttribute)))
            {
                continue;
            }

            var offsetAttribute =
                (NetFieldOffsetAttribute)property.GetCustomAttribute(typeof(NetFieldOffsetAttribute))!;
            totalSize = Math.Max(totalSize, offsetAttribute.Offset + offsetAttribute.Size);
        }

        var bufferLength = (int)Math.Ceiling((double)totalSize / 8);
        var buffer = new byte[bufferLength];

        foreach (var property in properties)
        {
            if (!Attribute.IsDefined(property, typeof(NetFieldOffsetAttribute)))
            {
                continue;
            }

            var offsetAttribute =
                (NetFieldOffsetAttribute)property.GetCustomAttribute(typeof(NetFieldOffsetAttribute))!;
            dynamic value = property.GetValue(obj)!; // 使用dynamic類(lèi)型動(dòng)態(tài)獲取屬性值
            SetBitValue(ref buffer, value, offsetAttribute.Offset, offsetAttribute.Size);
        }

        return buffer;
    }

    public static T ToFieldObject<T>(this byte[] buffer) where T : class, new()
    {
        var obj = new T();
        var properties = typeof(T).GetProperties();

        foreach (var property in properties)
        {
            if (!Attribute.IsDefined(property, typeof(NetFieldOffsetAttribute)))
            {
                continue;
            }

            var offsetAttribute =
                (NetFieldOffsetAttribute)property.GetCustomAttribute(typeof(NetFieldOffsetAttribute))!;
            dynamic value = GetValueFromBit(buffer, offsetAttribute.Offset, offsetAttribute.Size,
                property.PropertyType);
            property.SetValue(obj, value);
        }

        return obj;
    }

    /// <summary>
    /// 將值按位寫(xiě)入buffer
    /// </summary>
    /// <param name="buffer"></param>
    /// <param name="value"></param>
    /// <param name="offset"></param>
    /// <param name="size"></param>
    private static void SetBitValue(ref byte[] buffer, int value, int offset, int size)
    {
        var mask = (1 << size) - 1;
        buffer[offset / 8] |= (byte)((value & mask) << (offset % 8));
        if (offset % 8 + size > 8)
        {
            buffer[offset / 8 + 1] |= (byte)((value & mask) >> (8 - offset % 8));
        }
    }

    /// <summary>
    /// 從buffer中按位讀取值
    /// </summary>
    /// <param name="buffer"></param>
    /// <param name="offset"></param>
    /// <param name="size"></param>
    /// <param name="propertyType"></param>
    /// <returns></returns>
    private static dynamic GetValueFromBit(byte[] buffer, int offset, int size, Type propertyType)
    {
        var mask = (1 << size) - 1;
        var bitValue = (buffer[offset / 8] >> (offset % 8)) & mask;
        if (offset % 8 + size > 8)
        {
            bitValue |= (buffer[offset / 8 + 1] << (8 - offset % 8)) & mask;
        }

        dynamic result = Convert.ChangeType(bitValue, propertyType); // 根據(jù)屬性類(lèi)型進(jìn)行轉(zhuǎn)換
        return result;
    }
}

3. 優(yōu)化效果與總結(jié)

通過(guò)逐步優(yōu)化,我們從最初的Json序列化366字節(jié)減小到了使用普通二進(jìn)制序列化的152字節(jié),再進(jìn)一步使用位域技術(shù)優(yōu)化到了86字節(jié)。這種優(yōu)化在網(wǎng)絡(luò)傳輸中是非??捎^的,尤其是在需要傳輸大量數(shù)據(jù)的情況下。

本文通過(guò)一個(gè)示例案例,探討了C#對(duì)象二進(jìn)制序列化的優(yōu)化方法。通過(guò)使用位域技術(shù),我們實(shí)現(xiàn)了對(duì)數(shù)據(jù)包大小的極限壓縮,提高了網(wǎng)絡(luò)傳輸?shù)男?。這對(duì)于開(kāi)發(fā)C/S程序來(lái)說(shuō)是一種樂(lè)趣,也是追求極致性能的一種體現(xiàn)。

以上就是C#使用位域技術(shù)進(jìn)行對(duì)象二進(jìn)制序列化優(yōu)的詳細(xì)內(nèi)容,更多關(guān)于C#對(duì)象二進(jìn)制序列化的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C# 預(yù)處理器指令的用法

    C# 預(yù)處理器指令的用法

    本文主要介紹了C# 預(yù)處理器指令的用法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • C#修改IIS站點(diǎn)framework版本號(hào)的方法

    C#修改IIS站點(diǎn)framework版本號(hào)的方法

    這篇文章主要介紹了C#修改IIS站點(diǎn)framework版本號(hào)的方法,涉及C#調(diào)用使用ASP.NET IIS注冊(cè)工具Aspnet_regiis.exe進(jìn)行IIS站點(diǎn)framework版本號(hào)修改的方法,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-10-10
  • C#實(shí)現(xiàn)密碼驗(yàn)證與輸錯(cuò)密碼賬戶鎖定

    C#實(shí)現(xiàn)密碼驗(yàn)證與輸錯(cuò)密碼賬戶鎖定

    這篇文章介紹了C#實(shí)現(xiàn)密碼驗(yàn)證與輸錯(cuò)密碼賬戶鎖定的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-04-04
  • C#實(shí)現(xiàn)十進(jìn)制數(shù)轉(zhuǎn)換為十六進(jìn)制的幾種方式

    C#實(shí)現(xiàn)十進(jìn)制數(shù)轉(zhuǎn)換為十六進(jìn)制的幾種方式

    在C#中,十進(jìn)制和十六進(jìn)制轉(zhuǎn)換非常簡(jiǎn)單,本文給大家介紹了C#實(shí)現(xiàn)十進(jìn)制數(shù)轉(zhuǎn)換為十六進(jìn)制的幾種方式,并通過(guò)代碼示例講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2024-04-04
  • C#通過(guò)屬性名字符串獲取、設(shè)置對(duì)象屬性值操作示例

    C#通過(guò)屬性名字符串獲取、設(shè)置對(duì)象屬性值操作示例

    這篇文章主要介紹了C#通過(guò)屬性名字符串獲取、設(shè)置對(duì)象屬性值操作,結(jié)合實(shí)例形式總結(jié)分析了C#通過(guò)反射獲取對(duì)象屬性值并設(shè)置屬性值,獲取對(duì)象的所有屬性名稱(chēng)及類(lèi)型等相關(guān)操作技巧,需要的朋友可以參考下
    2020-03-03
  • C#中String和StringBuilder的簡(jiǎn)介與區(qū)別

    C#中String和StringBuilder的簡(jiǎn)介與區(qū)別

    今天小編就為大家分享一篇關(guān)于C#中String和StringBuilder的簡(jiǎn)介與區(qū)別,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2018-10-10
  • 解析C#拼接Json串的幾種方法

    解析C#拼接Json串的幾種方法

    本文主要介紹了C#拼接Json串的幾種方法,主要包括了4種方式,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-06-06
  • C# Linq延遲查詢的執(zhí)行實(shí)例代碼

    C# Linq延遲查詢的執(zhí)行實(shí)例代碼

    這篇文章主要介紹了C# Linq延遲查詢執(zhí)行的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • C# Marshal類(lèi)基本概念和入門(mén)實(shí)例講解

    C# Marshal類(lèi)基本概念和入門(mén)實(shí)例講解

    這篇文章主要介紹了C# Marshal類(lèi)基本概念和入門(mén)實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。
    2023-02-02
  • C# 文件下載之?dāng)帱c(diǎn)續(xù)傳實(shí)現(xiàn)代碼

    C# 文件下載之?dāng)帱c(diǎn)續(xù)傳實(shí)現(xiàn)代碼

    本篇文章主要介紹了C# 文件下載之?dāng)帱c(diǎn)續(xù)傳實(shí)現(xiàn)代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-01-01

最新評(píng)論