diff options
Diffstat (limited to 'src/qtvstools.core/Common/EnumExt.cs')
-rw-r--r-- | src/qtvstools.core/Common/EnumExt.cs | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/src/qtvstools.core/Common/EnumExt.cs b/src/qtvstools.core/Common/EnumExt.cs new file mode 100644 index 00000000..4ebcdacb --- /dev/null +++ b/src/qtvstools.core/Common/EnumExt.cs @@ -0,0 +1,199 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt VS Tools. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace QtVsTools.Common +{ + /// <summary> + /// Extended enum support: + /// * Customized cast of enum values to arbitrary types + /// </summary> + public static class EnumExt + { + /// <summary> + /// Wrapper for enum cast values. + /// </summary> + /// <typeparam name="T">Type of cast output</typeparam> + /// <remarks> + /// Cast attributes associated with enum values must implement this interface. + /// </remarks> + public interface ICast<T> + { + T Value { get; } + } + + /// <summary> + /// String cast attribute associated to an enum value. + /// </summary> + /// <example> + /// enum Foobar { + /// Foo, + /// [EnumExt.String("Bahr")] Bar + /// } + /// </example> + [AttributeUsage(AttributeTargets.All)] + public sealed class StringAttribute : Attribute, ICast<string> + { + public string Value { get; private set; } + public StringAttribute(string str) { Value = str; } + } + + /// <summary> + /// Cast enum value to type T. + /// </summary> + /// <typeparam name="T">Cast output type.</typeparam> + /// <param name="value">Input enum value.</param> + /// <returns> + /// Value of type T associated to the enum value by an Attribute implementing + /// ICast<typeparamref name="T"/>. If no attribute is found, returns a default value. + /// </returns> + /// <example> + /// enum Foobar + /// { + /// Foo, + /// [EnumExt.String("Bahr")] Bar + /// } + /// Foobar foo = Foobar.Foo; + /// Foobar bar = Foobar.Bar; + /// string fooCastString = foo.Cast<string>(); // "Foo" + /// string barCastString = bar.Cast<string>(); // "Bahr" + /// string fooToString = foo.ToString(); // "Foo" + /// string barToString = bar.ToString(); // "Bar" + /// </example> + public static T Cast<T>(this Enum value) + { + if (FindCastAttrib<T>(value) is ICast<T> cast) + return cast.Value; + else + return Default<T>(value); + } + + /// <summary> + /// Compare enum value with instance/value of type T. + /// </summary> + /// <typeparam name="T">Cast/comparison type.</typeparam> + /// <param name="valueT">Instance/value of type T to compare with.</param> + /// <param name="valueEnum">Enum value to compare with.</param> + /// <returns>true if cast of valueEnum is equal to valueT, false otherwise</returns> + public static bool EqualTo<T>(this T valueT, Enum valueEnum) + { + return valueT.Equals(valueEnum.Cast<T>()); + } + + /// <summary> + /// Convert type T to enum + /// </summary> + public static bool TryCast<T, TEnum>(this T valueT, out TEnum value) where TEnum : struct + { + value = default(TEnum); + IEnumerable<Enum> enumValues = Enum.GetValues(typeof(TEnum)).OfType<Enum>() + .Where((Enum valueEnum) => valueEnum.Cast<T>().Equals(valueT)); + if (enumValues.Any()) + value = (TEnum)Enum.ToObject(typeof(TEnum), enumValues.FirstOrDefault()); + return enumValues.Any(); + } + + /// <summary> + /// Get list of values of enum type converted to type T + /// </summary> + public static IEnumerable<T> GetValues<T>(Type enumType) + { + return Enum.GetValues(enumType).OfType<Enum>() + .Select((Enum value) => value.Cast<T>()); + } + + /// <summary> + /// Default cast of enum value to type T. + /// </summary> + /// <typeparam name="T">Cast output type.</typeparam> + /// <param name="value">Input enum value.</param> + /// <returns> + /// Default value of type T associated with the enum value: + /// * if T is string: returns the enum value name as string; + /// * if T is an integer type: returns the underlying enum integer value; + /// * otherwise: default value for type T (e.g. null for reference types). + /// </returns> + static T Default<T>(Enum value) + { + Type enumType = value.GetType(); + Type baseType = Enum.GetUnderlyingType(enumType); + Type outputType = typeof(T); + if (outputType.IsAssignableFrom(enumType) || outputType.IsAssignableFrom(baseType)) + return (T)(object)value; + else if (outputType == typeof(string)) + return (T)(object)Enum.GetName(value.GetType(), value); + else + return default(T); + } + + /// <summary> + /// Find cast attribute. + /// </summary> + /// <typeparam name="T">Cast output type.</typeparam> + /// <param name="value">Input enum value.</param> + /// <returns> + /// First cast attribute of type T found associated with the enum value, or null in case a + /// suitable attribute is not found. + /// </returns> + static ICast<T> FindCastAttrib<T>(Enum value) + { + Type enumType = value.GetType(); + + string valueName = Enum.GetName(enumType, value); + if (string.IsNullOrEmpty(valueName)) + return null; + + FieldInfo enumField = enumType.GetField(valueName); + if (enumField == null) + return null; + + return CastAttribTypes + .Where(type => typeof(ICast<T>).IsAssignableFrom(type)) + .Select(type => Attribute.GetCustomAttribute(enumField, type) as ICast<T>) + .FirstOrDefault(); + } + + static IEnumerable<Type> _CastAttribTypes; + /// <summary> + /// List of cast attribute types. + /// </summary> + /// <remarks> + /// Future cast attribute types need to be added to this list. + /// </remarks> + static IEnumerable<Type> CastAttribTypes => _CastAttribTypes + ?? (_CastAttribTypes = new[] + { + typeof(StringAttribute) + }); + + } +} |