向后按位的最佳方法

时间:2018-11-28 03:05:39

标签: c#

我想出了如何将我的位打包成一个16位的ushort,我的枚举是1-13,所以它们都应该适合。问题是我知道我可以以比以前更快的速度打开包装,可耻的是我不想发布可怕的代码。任何见识将是有益的。我的Push不是将其推送到字节数组的字符串,因此字符串将分解为单个字节。我的ushort分解为2个字节,float分解为4个字节,依此类推。这是我要完成的工作的图像。enter image description here

修订后的代码声明2018年11月27日晚上11:47

Enums.cs

public enum PacketFlags
{
    None = 0x1,
    Nat = 0x2,
    Hb = 0x4,
    Dat = 0x8,
    Dscvr = 0x16,
    Status = 0x20,
    Conn = 0x40,
    Finn = 0x80,
    ReliableOrdered = 0x100,
    Sequenced = 0x200, 
    NotFragged = 0x400,
    Frag = 0x800,
    Fragout = 0x1000,
}

有问题的方法

    public void WriteHeader()
    {
        Count = Ptr;
        var flag = Fragmented | Proto | Flag;
        var field = (ushort)flag;
        Ptr = 0;
        Push(field);
        Push(_id);
    }

    public void ReadHeader()
    {
        Ptr = 0;

        var header = PullUShort();
        var flags = (PacketFlags)header;
        SetFlag(flags);
        SetProto(flags);
        SetFrag(flags);
        _id = PullUShort();
    }

    private void SetFlag(PacketFlags flags)
    {
        //Set Flag
        if((flags & PacketFlags.None) != 0)
        {
            Flag = PacketFlags.None;
        }

        if ((flags & PacketFlags.Nat) != 0)
        {
            Flag = PacketFlags.Nat;
        }

        if ((flags & PacketFlags.Hb) != 0)
        {
            Flag = PacketFlags.Hb;
        }

        if ((flags & PacketFlags.Dat) != 0)
        {
            Flag = PacketFlags.Dat;
        }

        if ((flags & PacketFlags.Dscvr) != 0)
        {
            Flag = PacketFlags.Dscvr;
        }

        if ((flags & PacketFlags.Status) != 0)
        {
            Flag = PacketFlags.Status;
        }

        if ((flags & PacketFlags.Conn) != 0)
        {
            Flag = PacketFlags.Conn;
        }

        if ((flags & PacketFlags.Finn) != 0)
        {
            Flag = PacketFlags.Finn;
        }
    }

    private void SetProto(PacketFlags flags)
    {
        if ((flags & PacketFlags.ReliableOrdered) != 0)
        {
            Proto = PacketFlags.ReliableOrdered;
        }

        if ((flags & PacketFlags.Sequenced) != 0)
        {
            Flag = PacketFlags.Sequenced;
        }
    }

    private void SetFrag(PacketFlags flags)
    {
        if ((flags & PacketFlags.NotFragged) != 0)
        {
            Flag = PacketFlags.NotFragged;
        }

        if ((flags & PacketFlags.Frag) != 0)
        {
            Flag = PacketFlags.Frag;
        }

        if ((flags & PacketFlags.Fragout) != 0)
        {
            Flag = PacketFlags.Fragout;
        }
    }

请注意,我在.Net 3.5上,这是用于网络解决方案的。如果应用程序每秒处理40k +数据包,并且运行该方法的速度慢,则Enum.HasValue将使用反射。我并不是想轻松获得性能。

1 个答案:

答案 0 :(得分:4)

您正在尝试使用位位置指定标志。如果只使用这些位上的值,则更容易。

[Flags]
public enum PacketFlags : ushort
{
    None   = 0x01,  // this is the same as 1 << 1 = 1
    Nat    = 0x02,  // this is the same as 1 << 2 = 2
    Hb     = 0x04,  // this is the same as 1 << 3 = 4
    Dat    = 0x08,
    Dscvr  = 0x10,
    Status = 0x20,  // this is the same as 1 << 6 = 32
    Conn   = 0x40,
    Finn   = 0x80,
}

首先,“ none”通常被分配为零,但除此之外,让我们假设即使未设置任何标志,您的标志也将始终被置位。

两个,我以十六进制指定了标志值,但这不是必需的。如果愿意,可以使用简单的以10为底的数字。

三,[Flags] attribute的全部作用就是改变将枚举格式化为字符串时发生的情况。继续尝试。或将一些标志放在一起,然后在其上调用.ToString()。然后删除该属性,并注意差异。它很方便,但是没有做任何非常重要的事情。

现在,您的问题:

打包就像对它们进行按位或运算一样简单:

var flag = PacketFlags.Nat | PacketFlags.Hb;

现在,当您想要标记的数字表示形式时,可以将其强制转换为ushort

var imaNumber = (ushort)flag;  // equals 0x06.

您可以看到[Flags]属性的作用:

var inEnglish = flag.ToString(); // contains: "Nat, Hb"

解包就像将ushort值强制转换为PacketFlags一样简单:

var unpacked = (PacketFlags)imaNumber;  

然后您可以使用Enum.HasFlags检查是否设置了特定标志。

此答案旨在帮助您朝正确的方向开始。我可以根据需要修改它。看看可以先买到什么。