I currently have some crude google code.. that works but I want to swap to an enum.
Currently I need a byte to represent some bit flags that are set,
I currently have this:
BitArray bitArray =new BitArray(new bool[] { true, true, false, false, false, false, false, false });
used in line..
new byte[] {ConvertToByte(bitArray)})
with ConvertToByte from this site...
private static byte ConvertToByte(BitArray bits) // http://stackoverflow.com/questions/560123/convert-from-bitarray-to-byte
{
if (bits.Count != 8)
{
throw new ArgumentException("incorrect number of bits");
}
byte[] bytes = new byte[1];
bits.CopyTo(bytes, 0);
return bytes[0];
}
However I wanted to use an enum as I touched on, so I created it as so:
[Flags]
public enum EventMessageTypes
{
None = 0,
aaa = 1,
bbb = 2,
ccc = 4,
ddd = 8,
eee = 16,
fff = 32,
All = aaa | bbb | ccc | ddd | eee | fff // All Events
}
and then
// Do bitwise OR to combine the values we want
EventMessageTypes eventMessages = EventMessageTypes.aaa | EventMessageTypes.bbb | EventMessageTypes.ccc;
But how do I then get eventMessages to a byte (0x07) I think! so I can append that to my byte array?
just simply cast it to byte!.
example:
byte eventMessages =(byte)( EventMessageTypes.aaa | EventMessageTypes.bbb | EventMessageTypes.ccc);
You have a way of getting a byte, so now just cast:
byte b = ConvertToByte(bitArray);
EventMessageTypes a = (EventMessageTypes) b;
Also, a tip, restrict the enum range to byte to prevent someone later adding out of range values to the enum:
[Flags]
public enum EventMessageTypes : byte
{
...
}
Here's one way:
var bitArray = new BitArray(
new [] { true, true, false, false, false, false, false, false });
var eventMessages = (EventMessageTypes)bitArray
.Cast<Boolean>()
.Reverse()
.Aggregate(0, (agg, b) => (agg << 1) + (b ? 1 : 0));
Download for LinqPad
If I understand your problem right, then in essence you can cast to enum like this EventMessageTypes result = (EventMessageTypes)ConvertToByte(bitArray);
BitArray bitArray = new BitArray(new bool[]
{ true, true, false, false,
false, false, false, false });
EventMessageTypes b = (EventMessageTypes)ConvertToByte(bitArray);
you could for readability and future code reuse make a extension class
static class Extension
{
public static byte ToByte(this BitArray bits)
{
if (bits.Count != 8)
{
throw new ArgumentException("incorrect number of bits");
}
byte[] bytes = new byte[1];
bits.CopyTo(bytes, 0);
return bytes[0];
}
static class EnumConverter<TEnum> where TEnum : struct, IConvertible
{
public static readonly Func<long, TEnum> Convert = GenerateConverter();
static Func<long, TEnum> GenerateConverter()
{
var parameter = Expression.Parameter(typeof(long));
var dynamicMethod = Expression.Lambda<Func<long, TEnum>>(
Expression.Convert(parameter, typeof(TEnum)),
parameter);
return dynamicMethod.Compile();
}
}
public static T ToEnum<T>(this byte b) where T : struct, IConvertible
{
if (!typeof(T).IsEnum)
{
throw new ArgumentException("T must be an enumerated type");
}
return EnumConverter<T>.Convert(b);
}
}
Then you can write the convert like this. bitArray.ToByte() or even better like this EventMessageTypes b = bitArray.ToByte().ToEnum<EventMessageTypes>();
Related
I have a ushort array:
ushort[] testArray = new ushort[]{1, 2, 3, 4, 5};
How I can convert it to a bit Array. In the above example, a length of 5 * 16 bit array? Thanks in advance!
Pretty simple google search gives this BitArray Class
Example
using System.Collections;
int[] myInts = new int[5] { 6, 7, 8, 9, 10 };
BitArray myBA5 = new BitArray( myInts );
Update:
So I was interested in the problem and decided to complete a working solution. This is what I'd do to handle shorts. One thing though is I'm assuming the bits will still translate given that you aren't trying to re-interperate back (??) and just want to loop through the raw bits?
var shorts = new ushort[] { 5, 1 };
var numberOfInts = (int)Math.Ceiling((decimal)shorts.Length / 2);
var theInts = new int[numberOfInts];
var shortsPos = 0;
for (int i = 0; i < numberOfInts; i++)
{
theInts[i] = shorts[shortsPos + 1];
theInts[i] = theInts[i] | ((int)shorts[shortsPos] << 16);
shortsPos =+ 2;
//theInts[i].Dump();
}
var bitArr = new BitArray(theInts);
foreach (var bit in bitArr)
{
//bit.Dump();
}
I mocked this up in LinqPad hence the .Dump() statements so do you're own thing for testing. You may have to switch around the order and maybe shift the second in each pair...I'll leave that part for you to work out. Also if you just have a single value in your source ushort[] you'll get an error so work out the maths to sort that out too..
The result of the above is:
True
False
False
False
False
False
False
False
False
False
False
False
False
False
False
False
True
False
True
False
False
False
False
False
False
False
False
False
False
False
False
False
int[] testArray = new int[] { 1, 2, 3, 4, 5 };
Dictionary<int, int[]> convertData = new Dictionary<int, int[]>();
foreach (int x in testArray)
{
System.Collections.BitArray b = new System.Collections.BitArray(Convert.ToByte(x));
convertData[x] = b.Cast<bool>().Select(bit => bit ? 1 : 0).ToArray();
}
From this enum type:
public enum MySqlObjectType
{
Table = 1,
Procedure = 2,
View = 4,
Function = 8,
Trigger = 512,
User = 128,
Event = 256
}
I want to make something like this:
Options.Load[MySqlObjectType.Event] = true;
Options.Load[MySqlObjectType.Function] = false;
How field in Options class should look like so I can do something as above? And is it possible?
You just need a dictionary to store the enum -> boolean key/value pair:
public class Options
{
public Options()
{
Load = new Dictionary<MySqlObjectType, bool>();
}
public Dictionary<MySqlObjectType, bool> Load { get; set; }
}
As Ivan said, you probably just want a simple flags enum:
public enum MySqlObjectType
{
Table = 1,
Procedure = 2,
View = 4,
Function = 8,
Trigger = 512,
User = 128,
Event = 256
}
Note that all values should be powers of 2 and unique.
MySqlObjectType value = MySqlObjectType.Event | MySqlObjectType.User;
To check if a value is set, you can do:
if ((value & MySqlobjectType.Event) == MySqlObjectType.Event) {
I think you can also do this as of .NET Framework v4:
if (value.HasFlag(MySqlObjectType.Event)) {
An other way to create single flags enum is:
public enum MySqlObjectType
{
Table = 1 << 0,
Procedure = 1 << 1,
View = 1 << 2,
Function = 1 << 3,
Trigger = 1 << 9,
User = 1 << 7,
Event = 1 << 8
}
I was looking for a generic way, representing any type of enum as a bin/oct/dec/hex-based string value.
Convert.ToType(Byte,SByte,Int16,UInt16,....) provides support, converting based string to desired type. But Convert.ToString, have just basement support for Type byte (unsigned), short(signed), int(signed), long(long). If you don't pay attantion you'll try getting bin-based string from UInt.Max:
Convert.ToString(UInt.MaxValue, 2) But there is no base support for UInt32, so 2 is intepreted as IFormatProvider.
Hex has a ToString Formatprovider, but it gives diffrent output than. Convert.ToString(,16).
Conver.ToString((short)79,16) // 4F
((short)79).ToString("X") // 4f
I'll make it quick, no consequent implementation, signed / unsigned problems, casting traps. While working with enum, you dont have an enum generic support. virieté of possible enumbase types and so on.
All what I would like, is representing any enum as based string and cast based string back to desired enum.
I'have put a little effort and created 2 Converters for that, Code implementation are available on following gist:
BasedEnumConverter and Helper: https://gist.github.com/chubbson/816b24a59e5f7e90385e
BasedValueConverter https://gist.github.com/chubbson/375b535243c166d28119
void Main()
{
var os = Tshort.Convesionfailed.ToStringOct().Dump(); //000120
BasedEnumConverter<Tshort>.ParseEnumFromOct(os).Dump(); //Conversionfailed
var stsbbin = Tsbyte.BAD.ToStringBin().Dump(); //10000000
BasedEnumConverter<Tsbyte>.ParseEnumFromBin(stsbbin).Dump(); //BAD
var sinthex = Tint.OK.ToStringHex().Dump(); //00000080
BasedEnumConverter<Tint>.ParseEnumFromHex(sinthex).Dump(); //OK
}
enum Tenum : byte { A = 0, B = 1, OK = 128, BAD = 255, Convesionfailed = 80 }
enum Tbyte : byte { A = 0, B = 1, OK = 128, BAD = 255, Convesionfailed = 80 }
enum Tsbyte : sbyte { A = 0, B = 1, OK = 127, OK2 = 126, BAD = -128, BAD2 = -127, Convesionfailed = 80 }
enum Tshort : short { A = 0, B = 1, OK = 128, BAD = 255, Convesionfailed = 80 }
enum Tushort : ushort { A = 0, B = 1, OK = 128, BAD = 255, Convesionfailed = 80 }
enum Tint : int { A = 0, B = 1, OK = 128, BAD = 255, Convesionfailed = 80 }
enum Tuint: uint { A = 0, B = 1, OK = 128, BAD = 255, Convesionfailed = 80 }
enum Tlong : long { A = 0, B = 1, OK = 128, BAD = 255, Convesionfailed = 80 }
enum Tulong : ulong { A = 0, B = 1, OK = 128, BAD = 255, Convesionfailed = 80, Min = ulong.MinValue, Max = ulong.MaxValue}
Please Review the code, give me a hint about performance/oop, what is conceptually wrong or could be done better. My first (or second approach was trying to calc the values by self with some shift and stringappending, but i discarted this cuz of 8 enum base types)
Trying to get array of all possible flags from enum value, say 3 to array of {1, 2}.
I have an extension
internal static MyEnum[] GetFlags(this MyEnum modKey)
{
string[] splitStr = modKey.ToString().Split(new string[1] { ", " }, StringSplitOptions.RemoveEmptyEntries);
MyEnum[] flags = new MyEnum[splitStr.Length];
for (int i = 0; i < splitStr.Length; i++)
{
flags[i] = (MyEnum)Enum.Parse(typeof(MyEnum), splitStr[i]);
}
return flags;
}
...but it seems a bit wasteful for the purpose. Could this be done more effectively?
You can simply filter all possible values of the MyEnum to the ones in modKey:
internal static MyEnum[] GetFlags(this MyEnum modKey)
{
return Enum.GetValues(typeof(MyEnum))
.Cast<MyEnum>()
.Where(v => modKey.HasFlag(v))
.ToArray();
}
Edit
Based on the comment below, in case of combinations specified, the method should only return the combinations, not all flags set.
The solution is to loop through all flags set in the enum starting from the highest one. In each iteration, we have to add a flag to the result, and remove it from the iterated enum until it's empty:
internal static MyEnum[] GetFlags(this MyEnum modKey)
{
List<MyEnum> result = new List<MyEnum>();
while (modKey != 0)
{
var highestFlag = Enum.GetValues(typeof(MyEnum))
.Cast<MyEnum>()
.OrderByDescending(v => v)
.FirstOrDefault(v => modKey.HasFlag(v));
result.Add(highestFlag);
modKey ^= highestFlag;
}
return result.ToArray();
}
assuming your MyEnum has a Flags Attribute, to test if a flag is set the (standard?) way is to perform a binary & between your value and the flag you want to test:
so something like this should work:
internal static MyEnum[] GetFlags(this MyEnum modKey)
{
List<MyEnum> flags = new List<MyEnum>();
foreach (var flag in Enum.GetValues(typeof(MyEnum)))
{
if (modKey & flag == flag)
flags.Add((MyEnum)flag);
}
return flags.ToArray();
}
if you use .Net 4 or later, you can use HasFlag
if (modKey.HasFlag((MyEnum)flag))
...
Both answers don't do what (I think) is asked: get the elementary values from an enum value, not any composed values. One example where this may be useful is when one enum value must be used in a Contains statement in LINQ to a SQL backend that doesn't support HasFlag.
For this purpose I first created a method that returns elementary flags from an enum type:
public static class EnumUtil
{
public static IEnumerable<TEnum> GetFlags<TEnum>()
where TEnum : Enum
{
return Enum.GetValues(typeof(TEnum))
.Cast<TEnum>()
.Where(v =>
{
var x = Convert.ToInt64(v); // because enums can be Int64
return x != 0 && (x & (x - 1)) == 0;
// Checks whether x is a power of 2
// Example: when x = 16, the binary values are:
// x: 10000
// x-1: 01111
// x & (x-1): 00000
});
}
}
And then a method that returns elementary flags from an enum value:
public static IEnumerable<TEnum> GetFlags<TEnum>(this TEnum enumValue)
where TEnum : Enum
{
return GetFlags<TEnum>()
.Where(ev => enumValue.HasFlag(ev));
}
Usage
Taking this enum type:
[Flags]
public enum WeekDay
{
Monday = 1 << 0,
Tuesday = 1 << 1,
Wednesday = 1 << 2,
Thursday = 1 << 3,
Friday = 1 << 4,
Saturday = 1 << 5,
Sunday = 1 << 6,
BusinessDay = Monday | Tuesday | Wednesday | Thursday | Friday,
WeekendDay = Saturday | Sunday,
All = BusinessDay | WeekendDay
}
The statements (in Linqpad)...
string.Join(",", EnumUtil.GetFlags<WeekDay>()).Dump();
var t = WeekDay.Thursday | WeekDay.WeekendDay;
string.Join(",", t.GetFlags()).Dump();
t = WeekDay.All;
string.Join(",", t.GetFlags()).Dump();
...return this:
Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday
Thursday,Saturday,Sunday
Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday
Basic idea taken from this answer to my question on Code Review.
I try converting any C# object to System.UInt64[].
System.Byte[] to System.UInt64[].
double[] to System.UInt64[].
int[] to System.UInt64[].
Example, convert object f1, f2 to ulong b[]
object f1 = new Byte[3] { 1, 2, 3 };
ulong b[] = Convert<ulong>(f1); //--- ?
object f2 = new double[3] { 1, 2, 3 };
b = Convert<ulong>(f2); //--- ?
Output
b[0] = 1
b[1] = 2
b[3] = 3
tell me how to write the function code Convert<T>(object value), where T output type value ulong ?
restrictions: Framework 2.0, input type can be obtained from the object f.
It turned out the only way to make
ulong[] b = Array.ConvertAll((byte[])f, element => Convert.ToUInt64(element));
Unfortunately input type is not necessarily be byte []
Use a linq expression:
System.Byte[] source = new System.Byte[] { 1, 2, 3 };
// does not work: System.UInt64[] target = source.Cast<System.UInt64>().ToArray();
System.UInt64[] target = source.Select(b => (System.UInt64)b).ToArray();
This works for all datatypes in source which can be casted to 'System.UInt64'.
Edit:
As Thomas Levesque pointed out Cast<System.UInt64>()does not work here, so we must use a Select(ConvertFunction) here.
You can use Array.ConvertAll:
byte[] bytes = new byte[3] { 1, 2, 3 };
ulong[] ulongs = Array.ConvertAll<byte, ulong>(b => (ulong)b);
Solved the problem with this, but maybe there are better decisions
static T[] MyConvert<T>(object value){
T[] ret = null;
if (value is Array)
{
Array arr = value as Array;
ret = new T[arr.Length];
for (int i = 0 ; i < arr.Length; i++ )
{
ret[i] = (T)Convert.ChangeType(arr.GetValue(i), typeof(T));.
}
}
return ret;
}