Files
zszq-trs/YLErpWeb/App/EnumHelper.cs
2024-05-09 14:06:26 +08:00

121 lines
5.4 KiB
C#

// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.ComponentModel.DataAnnotations;
using System.Diagnostics.Contracts;
using System.Reflection;
namespace System.Web.Mvc.Html
{
public static class EnumHelper
{
/// <summary>
/// Gets a value indicating whether the given <paramref name="type"/> or an expression of this
/// <see cref="Type"/> is suitable for use in <see cref="GetSelectList(Type)"/> and <see
/// cref="SelectExtensions.EnumDropDownListFor{TModel,TEnum}(HtmlHelper{TModel}, Expression{Func{TModel, TEnum}})"/>
/// calls.
/// </summary>
/// <param name="type">The <see cref="Type"/> to check.</param>
/// <returns>
/// <see langword="true"/> if <see cref="GetSelectList(Type)"/> will not throw when passed given
/// <see cref="Type"/> and <see
/// cref="SelectExtensions.EnumDropDownListFor{TModel,TEnum}(HtmlHelper{TModel}, Expression{Func{TModel, TEnum}})"/>
/// will not throw when passed an expression of this <see cref="Type"/>; <see langword="false"/> otherwise.
/// </returns>
/// <remarks>
/// Currently returns <see langref="true"/> if the <paramref name="type"/> parameter is
/// non-<see langref="null"/>, is an <see langref="enum"/> type, and does not have a
/// <see cref="FlagsAttribute"/> attribute.
/// </remarks>
public static bool IsValidForEnumHelper(Type type)
{
bool isValid = false;
if (type != null)
{
// Type.IsEnum is false for Nullable<T> even if T is an enum. Check underlying type (if any).
// Do not support Enum type itself -- IsEnum property is false for that class.
Type checkedType = Nullable.GetUnderlyingType(type) ?? type;
if (checkedType.IsEnum)
{
isValid = !HasFlagsInternal(checkedType);
}
}
return isValid;
}
/// <summary>
/// Gets a list of <see cref="SelectListItem"/> objects corresponding to enum constants defined in the given
/// <paramref name="type"/>.
/// </summary>
/// <param name="type">The <see cref="Type"/> to evaluate.</param>
/// <returns> An <see cref="IList{SelectListItem}"/> for the given <paramref name="type"/>.</returns>
/// <remarks>
/// Throws if <see cref="IsValidForEnumHelper(Type)"/> returns <see langref="false"/> for the given
/// <paramref name="type"/>.
/// </remarks>
public static IList<SelectListItem> GetSelectList(Type type)
{
if (type == null)
{
throw new ArgumentNullException("type");
}
if (!IsValidForEnumHelper(type))
{
throw new ArgumentException("非枚举类型,不支持", "type");
}
IList<SelectListItem> selectList = new List<SelectListItem>();
// According to HTML5: "The first child option element of a select element with a required attribute and
// without a multiple attribute, and whose size is "1", must have either an empty value attribute, or must
// have no text content." SelectExtensions.DropDownList[For]() methods often generate a matching
// <select/>. Empty value for Nullable<T>, empty text for round-tripping an unrecognized value, or option
// label serves in some cases. But otherwise, ignoring this does not cause problems in either IE or Chrome.
Type checkedType = Nullable.GetUnderlyingType(type) ?? type;
if (checkedType != type)
{
// Underlying type was non-null so handle Nullable<T>; ensure returned list has a spot for null
selectList.Add(new SelectListItem { Text = String.Empty, Value = String.Empty, });
}
// Populate the list
const BindingFlags BindingFlags =
BindingFlags.DeclaredOnly | BindingFlags.GetField | BindingFlags.Public | BindingFlags.Static;
foreach (FieldInfo field in checkedType.GetFields(BindingFlags))
{
// fieldValue will be an numeric type (byte, ...)
object fieldValue = field.GetRawConstantValue();
selectList.Add(new SelectListItem { Text = GetDisplayName(field), Value = fieldValue.ToString(), });
}
return selectList;
}
private static bool HasFlagsInternal(Type type)
{
Contract.Assert(type != null);
FlagsAttribute attribute = type.GetCustomAttribute<FlagsAttribute>(inherit: false);
return attribute != null;
}
// Return non-empty name specified in a [Display] attribute for the given field, if any; field's name otherwise
private static string GetDisplayName(FieldInfo field)
{
DisplayAttribute display = field.GetCustomAttribute<DisplayAttribute>(inherit: false);
if (display != null)
{
string name = display.GetName();
if (!String.IsNullOrEmpty(name))
{
return name;
}
}
return field.Name;
}
}
}