/**************************************************************************** ** ** 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.Diagnostics; using System.Linq; using System.Reflection; namespace QtVsTools.Common { /// /// Extended enum support: /// * Customized cast of enum values to arbitrary types /// public static class EnumExt { static LazyFactory StaticLazy { get; } = new LazyFactory(); /// /// Wrapper for enum cast values. /// /// Type of cast output /// /// Cast attributes associated with enum values must implement this interface. /// public interface ICast { T Value { get; } } /// /// String cast attribute associated to an enum value. /// /// /// enum Foobar { /// Foo, /// [EnumExt.String("Bahr")] Bar /// } /// [AttributeUsage(AttributeTargets.All)] public sealed class StringAttribute : Attribute, ICast { public string Value { get; } public StringAttribute(string str) { Value = str; } } /// /// Cast enum value to type T. /// /// Cast output type. /// Input enum value. /// /// Value of type T associated to the enum value by an Attribute implementing /// ICast. If no attribute is found, returns a default value. /// /// /// enum Foobar /// { /// Foo, /// [EnumExt.String("Bahr")] Bar /// } /// Foobar foo = Foobar.Foo; /// Foobar bar = Foobar.Bar; /// string fooCastString = foo.Cast(); // "Foo" /// string barCastString = bar.Cast(); // "Bahr" /// string fooToString = foo.ToString(); // "Foo" /// string barToString = bar.ToString(); // "Bar" /// public static T Cast(this Enum value) { if (FindCastAttrib(value) is ICast cast) return cast.Value; else return Default(value); } /// /// Compare enum value with instance/value of type T. /// /// Cast/comparison type. /// Instance/value of type T to compare with. /// Enum value to compare with. /// true if cast of valueEnum is equal to valueT, false otherwise public static bool EqualTo(this T valueT, Enum valueEnum) { return valueT.Equals(valueEnum.Cast()); } /// /// Convert type T to enum /// public static bool TryCast(this T valueT, out TEnum value) where TEnum : struct { value = default(TEnum); IEnumerable enumValues = Enum.GetValues(typeof(TEnum)).OfType() .Where((Enum valueEnum) => valueEnum.Cast().Equals(valueT)); if (enumValues.Any()) value = (TEnum)Enum.ToObject(typeof(TEnum), enumValues.FirstOrDefault()); return enumValues.Any(); } /// /// Convert type T to enum /// public static TEnum Cast(this T valueT, TEnum defaultValue) where TEnum : struct { return TryCast(valueT, out TEnum value) ? value : defaultValue; } /// /// Get list of values of enum type /// public static IEnumerable GetValues() where TEnum : struct { Debug.Assert(typeof(TEnum).IsEnum); return Enum.GetValues(typeof(TEnum)).OfType(); } /// /// Get list of values of enum type converted to type T /// public static IEnumerable GetValues(Type enumType) { return Enum.GetValues(enumType).OfType() .Select((Enum value) => value.Cast()); } /// /// Default cast of enum value to type T. /// /// Cast output type. /// Input enum value. /// /// 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). /// static T Default(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); } /// /// Find cast attribute. /// /// Cast output type. /// Input enum value. /// /// First cast attribute of type T found associated with the enum value, or null in case a /// suitable attribute is not found. /// static ICast FindCastAttrib(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).IsAssignableFrom(type)) .Select(type => Attribute.GetCustomAttribute(enumField, type) as ICast) .FirstOrDefault(); } /// /// List of cast attribute types. /// /// /// Future cast attribute types need to be added to this list. /// static IEnumerable CastAttribTypes => StaticLazy.Get(() => CastAttribTypes, () => new[] { typeof(StringAttribute) }); } }