[VS2010] FlagCollection Class
[Visual Basic .NET version here]
I had the need for a project to quickly design a flexible system that can create boolean flags based on a name and allow for quickly setting/getting the value of them.
My first thought was to implement it as a Dictionary<string, bool>, but I was told that this needed to be serializable, which immediately axed the Dictionary idea as that is -not- serializable [I have tested, if someone finds out otherwise, let me know], so what I decided to do is recreate Dictionary-like attributes using only a List and a Structure.
Along the way, I realized that, as it being a list, I could only access the data using a numerical index:
Code:
List<Flag> list = new List<Flag>;
Flag F = new Flag();
F.Name = "XYZ";
F.Value = false;
list.Add(F);
Console.WriteLine(list[0].Value);
That's fine and dandy, but that doesn't help me when I'm dealing with names, and calling with names, and searching with names. So, I decided to implement System.Collections.Generic.List<FlagCollection.Flag> which gave me some more freedom over what to do with the list.
After working around for awhile, I figured out how to overload the item property, allowing me to change how I searched for data and also what was returned, so the above code could now be transformed:
Code:
List<Flag> list = new List<Flag>;
Flag F = new Flag();
F.Name = "XYZ";
F.Value = false;
list.Add(F);
Console.WriteLine(list["XYZ"]);
Both of those code snippets will produce the exact same result with this class now. I'm not sure how useful this class will be to someone, but I decided to post it up anyways; maybe someone will get some use out of it.
Enough rambling, here's the code.
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace FlagCollection
{
/// <summary>
/// An implementation if a flag collection system using a Generic List from the collections namespace
/// </summary>
public class FlagCollection : System.Collections.Generic.List<FlagCollection.Flag>
{
/// <summary>
/// An individual structure that contains data for a flag.
/// </summary>
[Serializable]
public struct Flag
{
/// <summary>
/// Returns or sets the Name of this flag.
/// </summary>
public string Name { get; set; }
/// <summary>
/// Returns or sets if the flag is set or not.
/// </summary>
public bool Value { get; set; }
}
/// <summary>
/// Adds a new flag to the flag collection. The return value indicates if the flag was successfully added.
/// </summary>
/// <param name="Name">The name of the flag to add.</param>
/// <param name="Value">The value to set the flag to.</param>
public bool Add(string Name, bool Value)
{
//Use a bit of LINQ magic.
var currentFlags = (from _flags in this where _flags.Name.Equals(Name) select _flags).ToList();
//Check
if (currentFlags.Count.Equals(0)) { this.Add(new Flag() { Name = Name, Value = Value }); return true; } else { return false; }
}
/// <summary>
/// Removes a Flag from the collection. The return value indicates if the removal was
/// successful.
/// </summary>
/// <param name="Name">The name of the flag to remove.</param>
/// <returns></returns>
public bool Remove(string Name)
{
//See if it even exists
var flagList = (from flag in this where flag.Name.Equals(Name) select flag).ToList();
//Check
if (flagList.Count.Equals(0)) { return false; } else { this.Remove(flagList[0]); return true; }
}
/// <summary>
/// Checks to see if a flag exists.
/// </summary>
/// <param name="Name">The name of the flag to check.</param>
/// <returns></returns>
public bool Exists(string Name)
{
return (from f in this where f.Name.Equals(Name) select f).ToList().Count.Equals(1);
}
/// <summary>
/// Returns the value of a flag.
/// </summary>
/// <param name="Name">The name of the flag to return.</param>
/// <exception cref="FlagNotFoundException">When thrown, the flag name will be passed.</exception>
/// <returns>Returns the value of the flag.</returns>
public bool GetFlagValue(string Name)
{
//LINQ Magic
var flags = (from flag in this where flag.Name.Equals(Name) select flag).ToList();
//Check
if (flags.Count.Equals(0)) { throw new FlagNotFoundException(Name); } else { return flags[0].Value; }
}
/// <summary>
/// Sets a flag with a new value.
/// </summary>
/// <param name="Name">The name of the flag to set.</param>
/// <param name="newValue">The new value of the flag.</param>
/// <exception cref="FlagNotFoundException">When thrown, the flag name will be passed.</exception>
/// <returns>A true or false indicating if the flag was set properly.</returns>
public bool SetFlagValue(string Name, bool newValue)
{
//LINQ Magic
var flags = (from flag in this where flag.Name.Equals(Name) select flag).ToList();
//Check
if (flags.Count.Equals(0)) { throw new FlagNotFoundException(Name); } else { this.Remove(Name); this.Add(Name, newValue); return true; }
}
/// <summary>
/// Returns or sets the value of the given flag.
/// </summary>
/// <param name="name">The name of the flag.</param>
/// <returns></returns>
public bool this[string name]
{
get
{
return this.GetFlagValue(name);
}
set
{
if (!this.Exists(name)) { this.Add(new Flag() { Name = name, Value = !object.ReferenceEquals(value, null) ? value : false }); } else { this.SetFlagValue(name, value); }
}
}
/// <summary>
/// Serializes all current flags to a byte array.
/// </summary>
/// <returns></returns>
public byte[] Save()
{
//Build a memory-stream
System.IO.MemoryStream ms = new System.IO.MemoryStream();
//Build the serializer
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
//Go ahead and save all the data
bf.Serialize(ms, this);
//Now get our byte array
byte[] data = ms.ToArray();
//Close the array
ms.Close();
//Return the data
return data;
}
/// <summary>
/// Deserializes all data from the byte array to the flags.
/// </summary>
/// <param name="data">The data to de-serialize.</param>
public void Load(byte[] data)
{
//Build a memory-stream
System.IO.MemoryStream ms = new System.IO.MemoryStream(data);
//Build the deserializer.
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
//Get all the data
var FlagData = bf.Deserialize(ms);
//close the stream
ms.Close();
//Clear our current data
this.Clear();
//assign the data
this.AddRange((List<Flag>)FlagData);
}
}
/// <summary>
/// This exception is thrown when the given flag does not exist.
/// </summary>
public class FlagNotFoundException : System.Exception
{
string _msg;
/// <summary>
/// The name of the flag being checked.
/// </summary>
public string Name { get; set; }
public override string Message { get { return _msg; } }
public override string ToString()
{
return string.Format("{0}{1}{2}", this.Message, Environment.NewLine, this.StackTrace);
//return base.ToString();
}
/// <summary>
/// Creates a new FlagNotFoundException.
/// </summary>
/// <param name="FlagName">The name of the flag.</param>
public FlagNotFoundException(string FlagName)
{
this.Name = FlagName;
_msg = string.Format("The flag '{0}' was not found in the collection!", FlagName);
}
}
}