제가 1,2,4,8,10,20,40,80 이라고 표기를 했기 때문에…
그럴수있습니다…ㅋㅋ 그래서 위에 정정했습니다
감사합니다
[Flags] 쓰면 좋은데…
Value값을 쓰지 않을 경우 기본적으로
1234…이 아닌 1,2,4,8로 변경만 할 수 있다면야 더 좋은 코드가 될거같은데으음…
Byte 안에 Bit를 쓰는 것이기 때문에 어느정도 숙련도가 있으신분들도 사용할거라 생각이 듭니다.
그렇기 때문에
Enum을 극대화로 쓰는 방법과 아니면 기본적으로 쓰면서 사용할 수 있는 방법으로 나뉘어 사용하면어떨까하네요!
PackeBuilder에는 물론 Append에는 Enum을 극대화로 쓴 경우의 기준에서 들어가는게 좋을거같구요…!
[Flags]
public enum MACHINE : byte
{
NONE = 0,
POWER = 1 << 0,
RIGHT = 1 << 1,
TOP = 1 << 2,
LIGHT = 1 << 3,
TEMP = 1 << 4,
RUN = 1 << 5,
SOUND = 1 << 6,
ETC = 1 << 7,
}
.
.
.
new PackeBuilder()
.Append(MACHINE.POWER | MACHINE.TOP)
.
.
.
코드가 늘어 나긴 하지만… enum 상수가 많을때 일일히 하드코딩으로 값을 할당하기 귀찮을때 그냥 시프트 연산해주는 확장 메서드를 이용하면…(?)
public static int GetFlagValue<T>(this T enumValue) where T : Enum
{
var pos = Array.IndexOf(Enum.GetValues(enumValue.GetType()), enumValue);
return 1 << pos;
}
MACHINE.TEMP.GetFlagValue<MACHINE>(); // 32
GetFlagValue<MACHINE>(); ← 매번 요거 붙여서 쓰는게 더 귀찮을려나요 ?? ㅋㅋㅋ
아 답글 달고 나서 또 보니, 그냥 제너레이터 이용할 수 있으면 특정 어트리뷰트 만들어서 Flag처리된 상수 값을 자동으로 할당 되도록 코드 생성해 주면 될것도 같군요
오 아니에요! 좋은거같아요!
그게 귀찮으면 Enum에 값 미리 적어서 쓰라고하는게…맞는거같아서요 ㅋ_ㅋ
이 방법도 해봤는데 뭔가 제가 잘 이해를 못했는지 …잘안되네요!
일반적인 Enum값 다중선택 즉 비트연산을 시도하면
Resharper에서는 경고 주던데, 기존은 어떤가요?
byte로 전환 하기 전에
해당 Enum에 Flag Attribute 있는지 여부만 확인할 수만 있다면 그걸로 괜찮을 것 같아요.
없을 경우에만 @aroooong 님께서 작성해주신 GetFlagValue<T>
만 호출하면 될테니까요.
기존이라하면 Resharper 사용하지 않는 상태를 말씀하시는거겠죠?
경고 같은 상황은 없었습니다!
[Flags]를 먹인 Enum과 아닌 것에서의 차이가 있었습니다.
public Enum Machine
{
A,
B,
C
}
////
[Flags]
public Enum MachineFlags
{
A = 0x01,
B = 0x02,
C = 0x04
}
Machine noneFlags = A | B;
Console.WriteLine("noneFlags = ${noneFlags}");
Machine flags = A | B;
Console.WriteLine("flags = ${flags }");
/*
noneFlags = B
flags = A | B
*/
Flags Enum을 적용하지 않은 Enum의 경우
byte 전환 전부터 이미 두개의 Enum 중 가장 큰 값만 적용되기 때문에
어떻게 할 수가 없더군요…
그래서 params Machine[]
을 생각해내서 아래와 같은 형태가 나오게되었습니다
EnumHelper.Byte (MACHINE.POWER, MACHINE.TOP);
제 경우는 열거형 정의할 때 어지간하면 Value 값을 일일이 지정하는 편입니다.
미리 잘 정의해 놓으면 편리하더라구요~ ㅎㅎ
특히 어떤 정의된 값을 다른 값들의 조합으로 재정의 할 때 주로 사용하죠~
예를 들면 이렇습니다.
[Flags]
public enum Docking : byte
{
None = 0b0000,
Left = 0b0001,
LeftTop = 0b0011,
Top = 0b0010,
TopRight = 0b0110,
Right = 0b0100,
RightBottom = 0b1100,
Bottom = 0b1000,
BottomLeft = 0b1001,
StratchH = 0b0101,
StratchV = 0b1010,
All = 0b1111,
}
네 맞아요
Enum을 극대화로! 쓰시는 케이스 말했던게 그 예제 입니다!
근데 극대화가 아닌 단순하게 사용하려는 목적이다 하는 경우를
@aroooong 님의 아이디어를 통해 개발 진행 중 입니다.
// 실제 코드
[BitSupportFlags]
public enum Docking
{
None ,
Left,
Top,
Right,
Bottom,
}
// 제네레이터된 코드
public enum Docking
{
None = 0x00,
Left = 0x01,
Top = 0x02,
Right = 0x04,
Bottom =0x08,
}
멋지군요~ㅎㅎ
기대하겠습니다~!
성공했는데…
Enum은 partial 쓸 수 없기 때문에…
// 실제 코드
[BitSupportFlags]
public enum Docking
{
None ,
Left,
Top,
Right,
Bottom,
}
// 제네레이트된 코드
public enum DockingFlags
{
None = 0x00,
Left = 0x01,
Top = 0x02,
Right = 0x04,
Bottom =0x08,
}
(Flags는 임시로 생성된…명칭)
Enum을 Flags화 시켰기 때문에 Flags가 붙는것도 나쁘지않을거같네요!
요런느낌으로 생성되게하면 원코드와의 상관관계가 좀더 명확해질거같은데 어떤가요?
// 실제 코드
[BitSupportFlags]
enum Docking : byte
{
Left, Top, Right, Bottom,
}
// 제네레이트된 코드
[Flags]
enum DockingFlags : byte
{
None,
Left = 1 << Docking.Left, // 0b00000001
Top = 1 << Docking.Top, // 0b00000010
Right = 1 << Docking.Right, // 0b00000100
Bottom = 1 << Docking.Bottom, // 0b00001000
}
static class DockingExtensions
{
public static DockingFlags ToFlags(this Docking d) => (DockingFlags)(1 << d);
}
오오…
좀 그럴싸하네요…!
한번 해보고공유드릴게요!
—
아 그리고 저 제네레이터기능은 현재 packetsupoort라이브러리에 들어갈순없고 아마 새로운 라이브러리로 해야할거같아요 …^^
제네레이터는 닷넷스탠다드2.0에서 된다고 하다보니…
추천해주신 방법대로
구현은 완료했습니다!
이 외에도 확장 기능 구현해보았습니다. HasAnyFlag
HasNotFlag
[BitSupportFlags]
enum Docking : byte
{
Left, Top, Right, Bottom,
}
// 제네레이트된 코드
[Flags]
enum DockingFlags : byte
{
None,
Left = 1 << Docking.Left, // 0b00000001
Top = 1 << Docking.Top, // 0b00000010
Right = 1 << Docking.Right, // 0b00000100
Bottom = 1 << Docking.Bottom, // 0b00001000
}
byte abc = 0x05;
var machine = data.ToEnum<MACHINEFlags> ();
if(machine.HasAnyFlag(Docking.Left)
{
Console.WriteLine("Docking Left은 포함되어있습니다.");
}
else if(machine.HasNotFlag(Docking.Top)
{
Console.WriteLine("Docking Top은 포함되어있지않습니다.");
}
/* output
Docking Left은 포함되어있습니다.
Docking Top은 포함되어있지않습니다.
*/
와웅 뚝딱 만들어버리시네요 기대가 됩니다
여태까지 만든 상황을 정리해보겠습니다!
기능
- [삭제] EnumHelper 확장메서드 기능 제거 - 소스생성기로 전부 이관 또는 다른 방법으로…
- [삭제] ToEumString - 불필요한 기능으로 인해서
- [구현] …Flags Enum 자동생성, NONE 누락 시 자동 생성됨
- [구현]
ToByte<T>
HasFlags
HasAnyFlags
HasNotFlags
4개의 확장메서드 제공
예제
[BitSupportFlags]
public enum MACHINE
{
POWER,
RIGHT,
TOP,
LIGHT,
TEMP,
RUN,
SOUND,
ETC
}
Flag 데이터를 통한 Byte 생성
var MACHINEFlags = MACHINE.POWER.ToFlags() | MACHINE.RIGHT.ToFlags(); // 또는 MACHINEFlags.POWER | MACHINEFlags.RIGHT
byte byteValue = aaa.ToByte ();
Byte를 통한 Enum 생성
byte byteValue = 0x05;
var enumData = byteValue.ToEnum<MACHINE> (); // 또는 data.ToEnum<MACHINEFlags>
…Flags의 Enum값만 HasFlags를 사용할 수 있음
byte byteValue = 0x05;
var enumData = byteValue.ToEnum<MACHINE> ();
if (enumData.HasFlags (MACHINEFlags.POWER | MACHINEFlags.TOP))
{
Console.WriteLine("POWER, TOP" 모두 포함된 Byte 데이터입니다.)
}
…Flags의 Enum의 값은 multi로데이터 사용 가능, Flags 아닌 경우엔 단일로만 사용가능
byte byteValue = 0x05;
var enumData = byteValue.ToEnum<MACHINE> ();
if (enumData.HasAnyFlags(MACHINEFlags.POWER | MACHINEFlags.TOP))
{
Console.WriteLine("POWER, TOP"이 포함된 Byte 데이터입니다.)
}
if (enumData.HasAnyFlags(MACHINE.POWER))
{
Console.WriteLine("POWER"이 포함된 Byte 데이터입니다.)
}
…Flags의 Enum의 값은 multi로데이터 사용 가능, Flags 아닌 경우엔 단일로만 사용가능
byte byteValue = 0x05;
var enumData = byteValue.ToEnum<MACHINE> ();
if (enumData.HasNotFlags(MACHINEFlags.NONE | MACHINEFlags.LIGHT))
{
Console.WriteLine("NONE , LIGHT"는 포함되어있지않습니다.)
}
if (enumData.HasNotFlags(MACHINE.POWER))
{
Console.WriteLine("POWER"는 포함되어있지않습니다.)
}