[英]"Decimal" flags (instead of binary) - built-in way?
我有這個從一些文檔中得到的公式,它應該解釋“標志”integer 代表什么:
Flags = Spectator * 1 + TemporarySpectator * 10 + PureSpectator * 100 + AutoTarget * 1000 + CurrentTargetId * 10000
我寫了這段代碼,它能夠將一個數字(標志)轉換為一些布爾值 + 一個 integer,就像在公式中一樣:
////////// From Values to Flag //////////
bool Spectator = true;
bool TemporarySpectator = false;
bool PureSpectator = true;
bool AutoTarget = false;
int CurrentTargetId = 255;
int Calculate() =>
(Convert.ToInt32(Spectator) * 1) +
(Convert.ToInt32(TemporarySpectator) * 10) +
(Convert.ToInt32(PureSpectator) * 100) +
(Convert.ToInt32(AutoTarget) * 1000) +
(Convert.ToInt32(CurrentTargetId) * 10000);
int Result = Calculate(); // 2550101
////////// From Flag to Values //////////
CurrentTargetId = Convert.ToInt32(Result / 10000);
AutoTarget = Convert.ToBoolean((Result - (CurrentTargetId * 10000)) / 1000);
PureSpectator = Convert.ToBoolean((Result - (CurrentTargetId * 10000) - (Convert.ToInt32(AutoTarget) * 1000)) / 100);
TemporarySpectator = Convert.ToBoolean((Result - (CurrentTargetId * 10000) - (Convert.ToInt32(AutoTarget) * 1000) - (Convert.ToInt32(PureSpectator) * 100)) / 10);
Spectator = Convert.ToBoolean((Result - (CurrentTargetId * 10000) - (Convert.ToInt32(AutoTarget) * 1000) - (Convert.ToInt32(PureSpectator) * 100) - (Convert.ToInt32(TemporarySpectator) * 100)) / 1);
Result = Calculate(); // 2550101
如您所見,我的代碼也能夠執行反向操作 - 將值轉換為標志。
我的代碼小提琴: https://do.netfiddle.net/ua2wi8
這種操作有什么名字嗎? 我知道枚舉的FlagsAttribute
類似但將標志存儲為單個位(“二進制數字”)而不是像我的情況那樣的十進制數字。
在 C# 中有沒有更簡單甚至是原生的方法來做到這一點? 使用來自 model class 的布爾值將是一個加號。
枚舉的FlagsAttribute
僅控制使用ToString
時枚舉的打印方式,並且它將在一個漂亮的逗號分隔列表中列出所有值。
您嘗試做的事情可以通過枚舉(最佳)實現,但如果您了解二進制或 2 的冪,也可以通過使用整數來實現。
public enum MyEnum {
Spectator = 1 << 0, // 1 or 2^0
TemporarySpectator = 1 << 1, // 2 or 2^1
PureSpectator = 1 << 2, // 4 or 2^2
AutoTarget = 1 << 3, // 8 or 2^3
CurrentTargetId = 1 << 4 // 16 or 2^4
}
MyEnum flags = MyEnum.Spectator | MyEnum.PureSpectator | MyEnum.CurrentTargetId;
////////// Extracting individual values from flags //////////
MyEnum currentTargetId = flags & MyEnum.CurrentTargetId;
MyEnum autoTarget = flags & MyEnum.AutoTarget;
MyEnum pureSpectator = flags & MyEnum.PureSpectator;
MyEnum temporarySpectator = flags & MyEnum.TemporarySpectator;
MyEnum spectator = flags & MyEnum.Spectator;
if (flags.HasFlag(MyEnum.AutoTarget))
{
// Do Stuff
}
if (flags.HasFlag(MyEnum.Spectator))
{
// Do Stuff
}
const int spectator = 0b_0000_0001; // 1 or 2^0
const int temporarySpectator = 0b_0000_0010; // 2 or 2^1
const int pureSpectator = 0b_0000_0100; // 4 or 2^2
const int autoTarget = 0b_0000_1000; // 8 or 2^3
const int currentTargetId = 0b_0001_0000; // 16 or 2^4
int flags = spectator | pureSpectator | currentTargetId;
////////// Extracting individual values from flags //////////
int currentTargetIdVal = flags & currentTargetId;
int autoTargetVal = flags & autoTarget;
int pureSpectatorVal = flags & pureSpectator;
int temporarySpectatorVal = flags & temporarySpectator;
int spectatorVal = flags & spectator;
if ((flags & autoTarget) > 0)
{
// Do Stuff
}
if ((flags & spectator) > 0)
{
// Do Stuff
}
C# 也允許使用Binary Literals ,所以MyEnum
也可以這樣寫:
public enum MyEnum {
Spectator = 0b_0000_0001,
TemporarySpectator = 0b_0000_0010,
PureSpectator = 0b_0000_0100,
AutoTarget = 0b_0000_1000,
CurrentTargetId = 0b_0001_0000
}
您可以將其全部包裝在 class 中,並使用取模運算符來簡化操作:
class DecimalFlags
{
private int _value = 0;
public bool Spectator
{
get
{
return _value % 10 == 1;
}
set
{
if (value && _value % 10 != 1) _value += 1;
else if (_value % 10 == 1) _value -= 1;
}
}
public bool TemporarySpectator
{
get
{
return (_value/10) % 10 == 1;
}
set
{
if (value && (_value/10) % 10 != 1) _value += 10;
else if ((_value/10) % 10 == 1) _value -= 10;
}
}
public bool PureSpectator
{
get
{
return (_value / 100) % 10 == 1;
}
set
{
if (value && (_value / 100) % 10 != 1) _value += 100;
else if ((_value / 100) % 10 == 1) _value -= 100;
}
}
public bool AutoTarget
{
get
{
return (_value / 1000) % 10 == 1;
}
set
{
if (value && (_value / 1000) % 10 != 1) _value += 1000;
else if ((_value / 1000) % 10 == 1) _value -= 1000;
}
}
public int CurrentTargetId {get;set;}
public static explicit operator int(DecimalFlags df)
{
return df._value + df.CurrentTargetId*10000;
}
public static explicit operator DecimalFlags(int i)
{
var df = new DecimalFlags();
df.CurrentTargetId = i/10000;
df._value = i - df.CurrentTargetId*10000;
return df;
}
}
然后當你需要將你的價值傳遞回游戲時,你可以說
MyGameFunction((int)decimalFlags);
或者從游戲中接收值:
int value = GetValueFromGame();
var decimalFlags = (DecimalFlags)value;
bool isSpectator = decimalFlags.Spectator; //etc
您可以創建自己的結構 object 來表示標志。 下面顯示的這個結構將以 8 個字節或long
的大小存儲所有標志和CurrentTaregtId
。 然后,您可以使用.Calculate
function 獲取您要查找的十進制值。 所有這些標志的值都可以達到255
,而十進制系統的缺點是每個值最多只能容納9
才能用作適當的“標志”。
請記住,此代碼尚未經過測試。 因此可能需要進行微小的改動。
[StructLayout(LayoutKind.Explicit)]
public struct MyFlags {
[FieldOffset(0)]
public ulong Value;
[FieldOffset(0)]
public byte Spectator;
[FieldOffset(1)]
public byte TemporarySpectator;
[FieldOffset(2)]
public byte PureSpectator;
[FieldOffset(3)]
public byte AutoTarget;
[FieldOffset(4)]
public uint CurrentTargetId;
public MyFlags(in ulong value) {
Value = value;
}
public MyFlags(in byte spectator, in byte temporarySpectator, in byte pureSpectator, in byte autoTarget, in uint currentTargetId) {
Spectator = spectator;
TemporarySpectator = temporarySpectator;
PureSpectator = pureSpectator;
AutoTarget = autoTarget;
CurrentTargetId = currentTargetId;
}
public long Calculate()
{
return Spectator
+ TemporarySpectator * 10
+ PureSpectator * 100
+ AutoTarget * 1000
+ CurrentTargetId * 10000;
}
}
/// Usage
MyFlags flags = new MyFlags();
flags.TemporarySpectator = 4;
flags.PureSpectator = 7;
flags.CurrentTargetId = 255;
flags.Calculate();
if (flags.AutoTarget > 0)
{
// Do stuff
}
以下是我最終使用手動字符串解析的方式:
public class SpectatorStatus : IFlag
{
public SpectatorStatus(int value)
{
var valueStr = value.ToString("D7");
const char True = '1';
CurrentTargetId = Convert.ToInt32(valueStr[..3]);
AutoTarget = valueStr[3] == True;
PureSpectator = valueStr[4] == True;
TemporarySpectator = valueStr[5] == True;
Spectator = valueStr[6] == True;
}
public bool Spectator { get; }
public bool TemporarySpectator { get; }
public bool PureSpectator { get; }
public bool AutoTarget { get; }
public int CurrentTargetId { get; }
public override string ToString()
=> (Convert.ToInt32(Spectator)
+ Convert.ToInt32(TemporarySpectator) * 10
+ Convert.ToInt32(PureSpectator) * 100
+ Convert.ToInt32(AutoTarget) * 1000
+ CurrentTargetId * 10000)
.ToString("D7");
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.