web-dev-qa-db-ja.com

Convert.ChangeTypeと列挙型への変換?

Int16値、データベースから、これを列挙型に変換する必要があります。残念ながら、これは、リフレクションを介して収集できるものを除いて、オブジェクトについてほとんど認識していないコードのレイヤーで行われます。

そのため、Convert.ChangeTypeは無効なキャスト例外で失敗します。

私は次のような臭いの回避策と考えるものを見つけました:

String name = Enum.GetName(destinationType, value);
Object enumValue = Enum.Parse(destinationType, name, false);

この文字列操作を行う必要がないように、より良い方法はありますか?

以下は、だれかが実験する必要がある場合に使用できる、短いが完全なプログラムです。

using System;

public class MyClass
{
    public enum DummyEnum
    {
        Value0,
        Value1
    }

    public static void Main()
    {
        Int16 value = 1;
        Type destinationType = typeof(DummyEnum);

        String name = Enum.GetName(destinationType, value);
        Object enumValue = Enum.Parse(destinationType, name, false);

        Console.WriteLine("" + value + " = " + enumValue);
    }
}

_Enum.ToObject(...._はあなたが探しているものです!

C#

_StringComparison enumValue = (StringComparison)Enum.ToObject(typeof(StringComparison), 5);
_

VB.NET

_Dim enumValue As StringComparison = CType([Enum].ToObject(GetType(StringComparison), 5), StringComparison)
_

多くのEnum変換を行う場合は、次のクラスを使用してみてください。これにより、コードを大幅に節約できます。

_public class Enum<EnumType> where EnumType : struct, IConvertible
{

    /// <summary>
    /// Retrieves an array of the values of the constants in a specified enumeration.
    /// </summary>
    /// <returns></returns>
    /// <remarks></remarks>
    public static EnumType[] GetValues()
    {
        return (EnumType[])Enum.GetValues(typeof(EnumType));
    }

    /// <summary>
    /// Converts the string representation of the name or numeric value of one or more enumerated constants to an equivalent enumerated object.
    /// </summary>
    /// <param name="name"></param>
    /// <returns></returns>
    /// <remarks></remarks>
    public static EnumType Parse(string name)
    {
        return (EnumType)Enum.Parse(typeof(EnumType), name);
    }

    /// <summary>
    /// Converts the string representation of the name or numeric value of one or more enumerated constants to an equivalent enumerated object.
    /// </summary>
    /// <param name="name"></param>
    /// <param name="ignoreCase"></param>
    /// <returns></returns>
    /// <remarks></remarks>
    public static EnumType Parse(string name, bool ignoreCase)
    {
        return (EnumType)Enum.Parse(typeof(EnumType), name, ignoreCase);
    }

    /// <summary>
    /// Converts the specified object with an integer value to an enumeration member.
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    /// <remarks></remarks>
    public static EnumType ToObject(object value)
    {
        return (EnumType)Enum.ToObject(typeof(EnumType), value);
    }
}
_

これで、_(StringComparison)Enum.ToObject(typeof(StringComparison), 5);_と書く代わりに、Enum<StringComparison>.ToObject(5);と書くことができます。

85
Peter

EnumをDataTableに格納しているが、どの列がenumでどの文字列/ intであるかわからない場合は、次の方法で値にアクセスできます。

foreach (DataRow dataRow in myDataTable.Rows)
{
    Trace.WriteLine("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");
    foreach (DataColumn dataCol in myDataTable.Columns)
    {
        object v = dataRow[dataCol];
        Type t = dataCol.DataType;
        bool e = false;
        if (t.IsEnum) e = true;

        Trace.WriteLine((dataCol.ColumnName + ":").PadRight(30) +
            (e ? Enum.ToObject(t, v) : v));
    }
}
0
Cassova

@Peterの回答に基づいて、ここに_Nullable<int>_からEnumへの変換方法があります。

_public static class EnumUtils
{
        public static bool TryParse<TEnum>(int? value, out TEnum result)
            where TEnum: struct, IConvertible
        {
            if(!value.HasValue || !Enum.IsDefined(typeof(TEnum), value)){
                result = default(TEnum);
                return false;
            }
            result = (TEnum)Enum.ToObject(typeof(TEnum), value);
            return true;
        }
}
_

EnumUtils.TryParse<YourEnumType>(someNumber, out result)の使用は、多くのシナリオで役立ちます。たとえば、Asp.NETのWebApiコントローラーには、無効なEnumパラメーターに対するデフォルトの保護がありません。 Asp.NETは、一部がnull、_-1000_、_500000_、_"garbage string"_を渡したり、パラメータを完全に無視したりしても、default(YourEnumType)値を使用します。さらに、ModelStateはこれらすべてのケースで有効であるため、解決策の1つはカスタムチェックで_int?_タイプを使用することです

_public class MyApiController: Controller
{
    [HttpGet]
    public IActionResult Get(int? myEnumParam){    
        MyEnumType myEnumParamParsed;
        if(!EnumUtils.TryParse<MyEnumType>(myEnumParam, out myEnumParamParsed)){
            return BadRequest($"Error: parameter '{nameof(myEnumParam)}' is not specified or incorrect");
        }      

        return this.Get(washingServiceTypeParsed);            
    }
    private IActionResult Get(MyEnumType myEnumParam){ 
       // here we can guarantee that myEnumParam is valid
    }
_
0
Artru