【问题标题】:Convert.ChangeType and converting to enums?Convert.ChangeType 并转换为枚举?
【发布时间】:2021-01-11 01:24:21
【问题描述】:

我从数据库中获得了一个Int16 值,需要将其转换为枚举类型。不幸的是,这是在代码层中完成的,除了可以通过反射收集到的对象之外,它对对象知之甚少。

因此,它最终调用 Convert.ChangeType 失败并出现无效的强制转换异常。

我发现了一个我认为很臭的解决方法,如下所示:

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

有没有更好的方法,让我不用通过这个String操作?

这是一个简短但完整的程序,如果有人需要进行实验,可以使用它:

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);
    }
}

【问题讨论】:

  • 哎哟...在我喝完咖啡之前,我需要停止尝试回答这样的问题...
  • 我现在看到了,Console.WriteLine 也在一个无法访问枚举类型的层中。我完全误解了。删除了我的(愚蠢的)答案。

标签: c# enums changetype


【解决方案1】:

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);
    }
}

现在你可以直接写Enum&lt;StringComparison&gt;.ToObject(5);,而不是写(StringComparison)Enum.ToObject(typeof(StringComparison), 5);

【讨论】:

  • 传奇!不知道这件事。是不是stackoverflow brill?! :-)
  • 因类似问题苦苦挣扎了一个多小时,终于解决了!即使在发布两年后也获得了 +1 ;)
  • ToObject() 似乎允许枚举中不存在的值以及基础类型范围之外的值:Enum.ToObject(typeof(IntEnumType), (long)Int32.MaxValue + 1)
  • @NelsonRothermel:C# 本身允许未在枚举中定义的枚举值,所以这并不奇怪。与强制转换相比,您的另一点更准确,但这似乎只是您的第一点的特例(它似乎首先强制转换为基础类型?)
  • 我多次看到这种方法(在智能感知中),但对它的任务有所了解。设计者可以给这个方法一个更直观的名字。
【解决方案2】:

根据@Peter 的回答,这里是Nullable&lt;int&gt;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&lt;YourEnumType&gt;(someNumber, out result) 在许多情况下都很有用。例如,Asp.NET 中的 WebApi 控制器没有针对无效枚举参数的默认保护。 Asp.NET 将只使用default(YourEnumType) 值,即使有些通过null-1000500000"garbage string" 或完全忽略该参数。此外,ModelState 在所有这些情况下都有效,因此解决方案之一是使用带有自定义检查的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
    }

【讨论】:

    【解决方案3】:

    如果您将 Enum 存储在 DataTable 中,但不知道哪一列是枚举,哪一列是字符串/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));
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2014-01-17
      • 1970-01-01
      • 1970-01-01
      • 2020-08-21
      • 2021-01-04
      • 1970-01-01
      • 2010-10-11
      相关资源
      最近更新 更多