// --------------------------------------------------------------------------------------------------------------------
// <copyright file="Enum.cs" company="Catel development team">
// Copyright (c) 2008 - 2011 Catel development team. All rights reserved.
// </copyright>
// <summary>
// Generic enumeration wrapper.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
namespace Catel
{
/// <summary>
/// Generic enumeration wrapper.
/// </summary>
/// <typeparam name="TEnum">Type of the enumeration to wrap.</typeparam>
public static class Enum<TEnum>
where TEnum : struct, IComparable, IFormattable
{
#region Constructors
/// <summary>
/// Initializes static members of the <see cref="Enum{TEnum}"/> class.
/// </summary>
static Enum()
{
Debug.Assert(typeof(TEnum).IsEnum, string.Format("The class ({0}) must be an enum", typeof(TEnum).FullName));
}
#endregion
#region Static Methods
#if !SILVERLIGHT
/// <summary>
/// Converts an enumaration to a list.
/// </summary>
/// <returns><see cref="List{TEnum}"/> containing all the values.</returns>
public static List<TEnum> ToList()
{
return Enum.GetValues(typeof(TEnum)).Cast<TEnum>().ToList();
}
#endif
/// <summary>
/// Gets the name.
/// </summary>
/// <param name="value">The value.</param>
/// <returns>The name of the value.</returns>
public static string GetName(int value)
{
return Enum.GetName(typeof(TEnum), value);
}
/// <summary>
/// Gets the name.
/// </summary>
/// <param name="value">The value.</param>
/// <returns>The name of the value.</returns>
public static string GetName(long value)
{
return Enum.GetName(typeof(TEnum), value);
}
#if !SILVERLIGHT
/// <summary>
/// Gets the names.
/// </summary>
/// <returns>Array of names of an enum.</returns>
public static string[] GetNames()
{
return Enum.GetNames(typeof(TEnum));
}
/// <summary>
/// Gets the values.
/// </summary>
/// <typeparam name="U">Type of the enum.</typeparam>
/// <returns><see cref="List{TEnum}"/> of values.</returns>
public static List<U> GetValues<U>()
{
Array array = Enum.GetValues(typeof(TEnum));
return array.Cast<U>().ToList();
}
#endif
/// <summary>
/// Tries to parse an enum value name.
/// </summary>
/// <param name="input">The input.</param>
/// <param name="result">The result.</param>
/// <returns><c>true</c> if successful; otherwise <c>false</c>.</returns>
public static bool TryParse(string input, out TEnum? result)
{
result = null;
if (!Enum.IsDefined(typeof(TEnum), input))
{
return false;
}
result = (TEnum)Enum.Parse(typeof(TEnum), input, true);
return true;
}
#if !SILVERLIGHT
/// <summary>
/// Tries to parse an enum value name.
/// </summary>
/// <param name="input">The input.</param>
/// <param name="result">The result.</param>
/// <returns><c>true</c> if successful; otherwise <c>false</c>.</returns>
public static bool TryParse(string input, out TEnum result)
{
TEnum? temp;
if (!TryParse(input, out temp))
{
// input not found in the Enum, fill the out parameter with the first item from the enum
Array values = Enum.GetValues(typeof(TEnum));
result = (TEnum)values.GetValue(values.GetLowerBound(0));
return false;
}
result = temp.Value;
return true;
}
#endif
/// <summary>
/// Gets the name.
/// </summary>
/// <param name="value">The value.</param>
/// <returns>The name of the value.</returns>
private static string GetName(TEnum value)
{
return Enum.GetName(typeof(TEnum), value);
}
#endregion
#region Nested type: DataBinding
/// <summary>
/// DataBinding class.
/// </summary>
public static class DataBinding
{
#region Delegates
/// <summary>
/// Delegate used for formatting an enum name.
/// </summary>
/// <param name="value">The value to format.</param>
/// <returns>String containing the enum name.</returns>
public delegate string FormatEnumName(TEnum value);
#endregion
#region Static Methods
#if !SILVERLIGHT
/// <summary>
/// Creates a list.
/// </summary>
/// <returns>Empty generic bindable enum list.</returns>
public static IList<IBindableEnum<TEnum>> CreateList()
{
return CreateList(null);
}
/// <summary>
/// Creates a list based on an enum.
/// </summary>
/// <param name="formatName">Name of the format.</param>
/// <returns>List containing bindable enums based on the format name.</returns>
public static IList<IBindableEnum<TEnum>> CreateList(FormatEnumName formatName)
{
var retVal = new List<IBindableEnum<TEnum>>();
Array values = Enum.GetValues(typeof(TEnum));
foreach (TEnum value in values)
{
retVal.Add(formatName != null ? new InternalBindableEnum(value, formatName(value)) : new InternalBindableEnum(value));
}
return retVal;
}
#endif
#endregion
#region Nested type: InternalBindableEnum
/// <summary>
/// Internal bindable enum.
/// </summary>
private class InternalBindableEnum : IBindableEnum<TEnum>
{
#region Readonly & Static Fields
/// <summary>
/// Name of the internal bindable enum.
/// </summary>
private readonly string name;
#endregion
#region Fields
/// <summary>
/// Value of the internal bindable enum.
/// </summary>
private TEnum value;
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="Enum{TEnum}.DataBinding.InternalBindableEnum"/> class.
/// </summary>
/// <param name="value">The value.</param>
public InternalBindableEnum(TEnum value)
{
this.value = value;
name = GetName(value);
}
/// <summary>
/// Initializes a new instance of the <see cref="Enum{TEnum}.DataBinding.InternalBindableEnum"/> class.
/// </summary>
/// <param name="value">The value of the internal bindable enum.</param>
/// <param name="name">The name of the internal bindable enum.</param>
public InternalBindableEnum(TEnum value, string name)
{
this.value = value;
this.name = name;
}
#endregion
#region Instance Properties
/// <summary>
/// Gets the name.
/// </summary>
/// <value>The name of the enum.</value>
public string Name
{
get { return name; }
}
/// <summary>
/// Gets the value.
/// </summary>
/// <value>The value of the enum.</value>
public TEnum Value
{
get { return value; }
}
#endregion
#region Instance Public Methods
/// <summary>
/// Compares the current object with another object of the same type.
/// </summary>
/// <param name="other">An object to compare with this object.</param>
/// <returns>
/// A 32-bit signed integer that indicates the relative order of the objects being compared.
/// The return value has the following meanings: Value Meaning Less than zero This object is less
/// than the other parameter. Zero This object is equal to other. Greater than zero This object is
/// greater than other.
/// </returns>
public int CompareTo(IBindableEnum<TEnum> other)
{
return value.CompareTo(other);
}
/// <summary>
/// Determines whether the specified <see cref="System.Object"/> is equal to this instance.
/// </summary>
/// <param name="other">The <see cref="System.Object"/> to compare with this instance.</param>
/// <returns>
/// <c>true</c> if the specified <see cref="System.Object"/> is equal to this instance; otherwise, <c>false</c>.
/// </returns>
/// <exception cref="T:System.NullReferenceException">
/// The <paramref name="other"/> parameter is null.
/// </exception>
public bool Equals(IBindableEnum<TEnum> other)
{
return value.Equals(other.Value);
}
#endregion
}
#endregion
}
#endregion
#region Nested type: Flags
/// <summary>
/// Flags class.
/// </summary>
public static class Flags
{
/// <summary>
/// Type code of the flags.
/// </summary>
private static readonly TypeCode typeCode;
#region Constructors
/// <summary>
/// Initializes static members of the <see cref="Enum{TEnum}.Flags"/> class.
/// </summary>
static Flags()
{
typeCode = Type.GetTypeCode(typeof(TEnum));
Debug.Assert(typeof(TEnum).IsDefined(typeof(FlagsAttribute), false),
string.Format("The Enum ({0}) must have the System.FlagsAttribute applied to it.", typeof(TEnum).FullName));
}
#endregion
#region Static Methods
/// <summary>
/// Clears the flag.
/// </summary>
/// <param name="flags">The flags.</param>
/// <param name="flagToClear">The flag to clear.</param>
/// <returns>Flags without the flag that should be cleared.</returns>
public static TEnum ClearFlag(TEnum flags, TEnum flagToClear)
{
if (typeCode == TypeCode.Int64)
{
return ClearFlag(Convert.ToInt64(flags, CultureInfo.CurrentCulture), Convert.ToInt64(flagToClear, CultureInfo.CurrentCulture));
}
else
{
// all other integral types except unsigned* which are not yet supported....
return ClearFlag(Convert.ToInt32(flags, CultureInfo.CurrentCulture), Convert.ToInt32(flagToClear, CultureInfo.CurrentCulture));
}
}
/// <summary>
/// Clears the flag.
/// </summary>
/// <param name="flags">The flags.</param>
/// <param name="flagToClear">The flag to clear.</param>
/// <returns>Flags without the flag that should be cleared.</returns>
public static TEnum ClearFlag(int flags, TEnum flagToClear)
{
return ClearFlag(flags, Convert.ToInt32(flagToClear, CultureInfo.CurrentCulture));
}
/// <summary>
/// Clears the flag.
/// </summary>
/// <param name="flags">The flags.</param>
/// <param name="flagToClear">The flag to clear.</param>
/// <returns>Flags without the flag that should be cleared.</returns>
public static TEnum ClearFlag(long flags, TEnum flagToClear)
{
return ClearFlag(flags, Convert.ToInt64(flagToClear, CultureInfo.CurrentCulture));
}
/// <summary>
/// Clears the flag.
/// </summary>
/// <param name="flags">The flags.</param>
/// <param name="flagToClear">The flag to clear.</param>
/// <returns>Flags without the flag that should be cleared.</returns>
public static TEnum ClearFlag(int flags, int flagToClear)
{
if (IsFlagSet(flags, flagToClear))
{
flags &= ~flagToClear;
}
return (TEnum)Enum.ToObject(typeof(TEnum), flags);
}
/// <summary>
/// Clears the flag.
/// </summary>
/// <param name="flags">The flags.</param>
/// <param name="flagToClear">The flag to clear.</param>
/// <returns>Flags without the flag that should be cleared.</returns>
public static TEnum ClearFlag(long flags, long flagToClear)
{
if (IsFlagSet(flags, flagToClear))
{
flags &= ~flagToClear;
}
return (TEnum)Enum.ToObject(typeof(TEnum), flags);
}
/// <summary>
/// Determines whether a specific flag is set.
/// </summary>
/// <param name="flags">The flags.</param>
/// <param name="flagToFind">The flag to find.</param>
/// <returns>
/// <c>true</c> if the flag is set; otherwise, <c>false</c>.
/// </returns>
public static bool IsFlagSet(TEnum flags, TEnum flagToFind)
{
if (typeCode == TypeCode.Int64)
{
return IsFlagSet(Convert.ToInt64(flags, CultureInfo.CurrentCulture), Convert.ToInt64(flagToFind, CultureInfo.CurrentCulture));
}
// all other integral types except unsigned* which are not yet supported....
return IsFlagSet(Convert.ToInt32(flags, CultureInfo.CurrentCulture), Convert.ToInt32(flagToFind, CultureInfo.CurrentCulture));
}
/// <summary>
/// Determines whether a specific flag is set.
/// </summary>
/// <param name="flags">The flags.</param>
/// <param name="flagToFind">The flag to find.</param>
/// <returns>
/// <c>true</c> if the flag is set; otherwise, <c>false</c>.
/// </returns>
public static bool IsFlagSet(int flags, TEnum flagToFind)
{
return IsFlagSet(Convert.ToInt32(flags, CultureInfo.CurrentCulture), Convert.ToInt32(flagToFind, CultureInfo.CurrentCulture));
}
/// <summary>
/// Determines whether a specific flag is set.
/// </summary>
/// <param name="flags">The flags.</param>
/// <param name="flagToFind">The flag to find.</param>
/// <returns>
/// <c>true</c> if the flag is set; otherwise, <c>false</c>.
/// </returns>
public static bool IsFlagSet(long flags, TEnum flagToFind)
{
return IsFlagSet(Convert.ToInt64(flags, CultureInfo.CurrentCulture), Convert.ToInt32(flagToFind, CultureInfo.CurrentCulture));
}
/// <summary>
/// Determines whether a specific flag is set.
/// </summary>
/// <param name="flags">The flags.</param>
/// <param name="flagToFind">The flag to find.</param>
/// <returns>
/// <c>true</c> if the flag is set; otherwise, <c>false</c>.
/// </returns>
public static bool IsFlagSet(int flags, int flagToFind)
{
return (flags & flagToFind) == flagToFind;
}
/// <summary>
/// Determines whether a specific flag is set.
/// </summary>
/// <param name="flags">The flags.</param>
/// <param name="flagToFind">The flag to find.</param>
/// <returns>
/// <c>true</c> if the flag is set; otherwise, <c>false</c>.
/// </returns>
public static bool IsFlagSet(long flags, long flagToFind)
{
return (flags & flagToFind) == flagToFind;
}
/// <summary>
/// Sets the flag.
/// </summary>
/// <param name="flags">The flags.</param>
/// <param name="flagToSet">The flag to set.</param>
/// <returns>Flags with the flag that should be set.</returns>
public static TEnum SetFlag(TEnum flags, TEnum flagToSet)
{
if (typeCode == TypeCode.Int64)
{
return SetFlag(Convert.ToInt64(flags, CultureInfo.CurrentCulture), Convert.ToInt64(flagToSet, CultureInfo.CurrentCulture));
}
else
{
// all other integral types except unsigned* which are not yet supported....
return SetFlag(Convert.ToInt32(flags, CultureInfo.CurrentCulture), Convert.ToInt32(flagToSet, CultureInfo.CurrentCulture));
}
}
/// <summary>
/// Sets the flag.
/// </summary>
/// <param name="flags">The flags.</param>
/// <param name="flagToSet">The flag to set.</param>
/// <returns>Flags with the flag that should be set.</returns>
public static TEnum SetFlag(int flags, TEnum flagToSet)
{
return SetFlag(flags, Convert.ToInt32(flagToSet, CultureInfo.CurrentCulture));
}
/// <summary>
/// Sets the flag.
/// </summary>
/// <param name="flags">The flags.</param>
/// <param name="flagToSet">The flag to set.</param>
/// <returns>Flags with the flag that should be set.</returns>
public static TEnum SetFlag(long flags, TEnum flagToSet)
{
return SetFlag(flags, Convert.ToInt64(flagToSet, CultureInfo.CurrentCulture));
}
/// <summary>
/// Sets the flag.
/// </summary>
/// <param name="flags">The flags.</param>
/// <param name="flagToSet">The flag to set.</param>
/// <returns>Flags with the flag that should be set.</returns>
public static TEnum SetFlag(int flags, int flagToSet)
{
if (!IsFlagSet(flags, flagToSet))
{
flags |= flagToSet;
}
return (TEnum)Enum.ToObject(typeof(TEnum), flags);
}
/// <summary>
/// Sets the flag.
/// </summary>
/// <param name="flags">The flags.</param>
/// <param name="flagToSet">The flag to set.</param>
/// <returns>Flags with the flag that should be set.</returns>
public static TEnum SetFlag(long flags, long flagToSet)
{
if (!IsFlagSet(flags, flagToSet))
{
flags |= flagToSet;
}
return (TEnum)Enum.ToObject(typeof(TEnum), flags);
}
/// <summary>
/// Swaps the flag.
/// </summary>
/// <param name="flags">The flags.</param>
/// <param name="flagToSwap">The flag to swap.</param>
/// <returns>Flags with the flag swapped that should be swapped.</returns>
public static TEnum SwapFlag(TEnum flags, TEnum flagToSwap)
{
if (typeCode == TypeCode.Int64)
{
return SwapFlag(Convert.ToInt64(flags, CultureInfo.CurrentCulture), Convert.ToInt64(flagToSwap, CultureInfo.CurrentCulture));
}
else
{
// all other integral types except unsigned* which are not yet supported....
return SwapFlag(Convert.ToInt32(flags, CultureInfo.CurrentCulture), Convert.ToInt32(flagToSwap, CultureInfo.CurrentCulture));
}
}
/// <summary>
/// Swaps the flag.
/// </summary>
/// <param name="flags">The flags.</param>
/// <param name="flagToSwap">The flag to swap.</param>
/// <returns>Flags with the flag swapped that should be swapped.</returns>
public static TEnum SwapFlag(int flags, TEnum flagToSwap)
{
return SwapFlag(flags, Convert.ToInt32(flagToSwap, CultureInfo.CurrentCulture));
}
/// <summary>
/// Swaps the flag.
/// </summary>
/// <param name="flags">The flags.</param>
/// <param name="flagToSwap">The flag to swap.</param>
/// <returns>Flags with the flag swapped that should be swapped.</returns>
public static TEnum SwapFlag(long flags, TEnum flagToSwap)
{
return SwapFlag(flags, Convert.ToInt64(flagToSwap, CultureInfo.CurrentCulture));
}
/// <summary>
/// Swaps the flag.
/// </summary>
/// <param name="flags">The flags.</param>
/// <param name="flagToSwap">The flag to swap.</param>
/// <returns>Flags with the flag swapped that should be swapped.</returns>
public static TEnum SwapFlag(int flags, int flagToSwap)
{
if (IsFlagSet(flags, flagToSwap))
{
return ClearFlag(flags, flagToSwap);
}
return SetFlag(flags, flagToSwap);
}
/// <summary>
/// Swaps the flag.
/// </summary>
/// <param name="flags">The flags.</param>
/// <param name="flagToSwap">The flag to swap.</param>
/// <returns>Flags with the flag swapped that should be swapped.</returns>
public static TEnum SwapFlag(long flags, long flagToSwap)
{
if (IsFlagSet(flags, flagToSwap))
{
return ClearFlag(flags, flagToSwap);
}
return SetFlag(flags, flagToSwap);
}
#endregion
}
#endregion
}
/// <summary>
/// Bindable enumeration.
/// </summary>
/// <typeparam name="T">Type of the enum to bind.</typeparam>
public interface IBindableEnum<T> : IComparable<IBindableEnum<T>>, IEquatable<IBindableEnum<T>>
where T : struct, IComparable, IFormattable
{
/// <summary>
/// Gets the name.
/// </summary>
/// <value>The name of the bindable enum.</value>
string Name { get; }
/// <summary>
/// Gets the value.
/// </summary>
/// <value>The value of the bindable enum.</value>
T Value { get; }
}
}