확장 함수를 작성 중입니다.Enum.Parse
그 개념
그래서 나는 다음과 같이 썼다.
public static T GetEnumFromString<T>(string value, T defaultValue) where T : Enum
{
if (string.IsNullOrEmpty(value)) return defaultValue;
foreach (T item in Enum.GetValues(typeof(T)))
{
if (item.ToString().ToLower().Equals(value.Trim().ToLower())) return item;
}
return defaultValue;
}
오류 제한이 특별 수업이 될 수 없습니다.System.Enum
.
공평하지만, 일반 열거 형을 허용하는 해결 방법이 있습니까, 아니면 일반 열거 형을 모방해야합니다.Parse
함수를 사용하고 코드로 추한 복싱 요구 사항을 강제로 특성으로 유형을 전달합니다.
편집하다아래의 모든 제안을 크게 감사드립니다.
정착했다 (나는 대소 문자를 구분하지 않기 위해 루프를 떠났다. XML을 파싱 할 때 이것을 사용하고있다)
public static class EnumUtils
{
public static T ParseEnum<T>(string value, T defaultValue) where T : struct, IConvertible
{
if (!typeof(T).IsEnum) throw new ArgumentException("T must be an enumerated type");
if (string.IsNullOrEmpty(value)) return defaultValue;
foreach (T item in Enum.GetValues(typeof(T)))
{
if (item.ToString().ToLower().Equals(value.Trim().ToLower())) return item;
}
return defaultValue;
}
}
편집하다:(2015 년 2 월 16 일) Julien Lebosquain이 최근에 게시했습니다.컴파일러가 MSIL 또는 F #아래는 잘 볼만한 가치가 있으며 upvote입니다. 솔루션이 페이지 위로 올라가는 경우이 편집을 제거합니다.
이후Enum
유형 구현IConvertible
인터페이스를 구현하려면 다음과 같이 구현해야합니다.
public T GetEnumFromString<T>(string value) where T : struct, IConvertible
{
if (!typeof(T).IsEnum)
{
throw new ArgumentException("T must be an enumerated type");
}
//...
}
이것은 여전히 구현하는 값 유형의 전달을 허용합니다.IConvertible
. 기회는 드뭅니다.
다음 스 니펫 (에서닷넷 샘플)는 다음을 사용함을 보여줍니다.
public static Dictionary<int, string> EnumNamedValues<T>() where T : System.Enum
{
var result = new Dictionary<int, string>();
var values = Enum.GetValues(typeof(T));
foreach (int item in values)
result.Add(item, Enum.GetName(typeof(T), item));
return result;
}
C # 프로젝트의 언어 버전을 버전 7.3으로 설정하십시오.
원문 아래의 답변 :
나는 게임에 늦었지만 어떻게 할 수 있는지보기 위해 도전으로 생각했다. C # (또는 VB.NET에서는 가능하지 않지만 F #에서는 아래로 스크롤)가능하다MSIL에서. 나는이 작은 .... 것을 썼다.
// license: http://www.apache.org/licenses/LICENSE-2.0.html
.assembly MyThing{}
.class public abstract sealed MyThing.Thing
extends [mscorlib]System.Object
{
.method public static !!T GetEnumFromString<valuetype .ctor ([mscorlib]System.Enum) T>(string strValue,
!!T defaultValue) cil managed
{
.maxstack 2
.locals init ([0] !!T temp,
[1] !!T return_value,
[2] class [mscorlib]System.Collections.IEnumerator enumerator,
[3] class [mscorlib]System.IDisposable disposer)
// if(string.IsNullOrEmpty(strValue)) return defaultValue;
ldarg strValue
call bool [mscorlib]System.String::IsNullOrEmpty(string)
brfalse.s HASVALUE
br RETURNDEF // return default it empty
// foreach (T item in Enum.GetValues(typeof(T)))
HASVALUE:
// Enum.GetValues.GetEnumerator()
ldtoken !!T
call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
call class [mscorlib]System.Array [mscorlib]System.Enum::GetValues(class [mscorlib]System.Type)
callvirt instance class [mscorlib]System.Collections.IEnumerator [mscorlib]System.Array::GetEnumerator()
stloc enumerator
.try
{
CONDITION:
ldloc enumerator
callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
brfalse.s LEAVE
STATEMENTS:
// T item = (T)Enumerator.Current
ldloc enumerator
callvirt instance object [mscorlib]System.Collections.IEnumerator::get_Current()
unbox.any !!T
stloc temp
ldloca.s temp
constrained. !!T
// if (item.ToString().ToLower().Equals(value.Trim().ToLower())) return item;
callvirt instance string [mscorlib]System.Object::ToString()
callvirt instance string [mscorlib]System.String::ToLower()
ldarg strValue
callvirt instance string [mscorlib]System.String::Trim()
callvirt instance string [mscorlib]System.String::ToLower()
callvirt instance bool [mscorlib]System.String::Equals(string)
brfalse.s CONDITION
ldloc temp
stloc return_value
leave.s RETURNVAL
LEAVE:
leave.s RETURNDEF
}
finally
{
// ArrayList's Enumerator may or may not inherit from IDisposable
ldloc enumerator
isinst [mscorlib]System.IDisposable
stloc.s disposer
ldloc.s disposer
ldnull
ceq
brtrue.s LEAVEFINALLY
ldloc.s disposer
callvirt instance void [mscorlib]System.IDisposable::Dispose()
LEAVEFINALLY:
endfinally
}
RETURNDEF:
ldarg defaultValue
stloc return_value
RETURNVAL:
ldloc return_value
ret
}
}
어떤 함수를 생성할 것이다그것이 C #이라면 이렇게 보일 것입니다.
T GetEnumFromString<T>(string valueString, T defaultValue) where T : Enum
다음 C # 코드를 사용합니다.
using MyThing;
// stuff...
private enum MyEnum { Yes, No, Okay }
static void Main(string[] args)
{
Thing.GetEnumFromString("No", MyEnum.Yes); // returns MyEnum.No
Thing.GetEnumFromString("Invalid", MyEnum.Okay); // returns MyEnum.Okay
Thing.GetEnumFromString("AnotherInvalid", 0); // compiler error, not an Enum
}
불행히도 이것은 C # 대신 MSIL로 작성된 코드의 일부분을 갖는 것입니다. 단, 추가 된 이점은이 메소드를 다음과 같이 제한 할 수 있다는 것입니다.System.Enum
. 별도의 어셈블리로 컴파일되기 때문에 일종의 허풍입니다. 그러나 그런 식으로 배포해야한다는 의미는 아닙니다.
라인을 제거함으로써.assembly MyThing{}
다음과 같이 ilasm을 호출합니다.
ilasm.exe /DLL /OUTPUT=MyThing.netmodule
어셈블리 대신 netmodule을 얻습니다.
불행하게도, VS2010 (그리고 이전 버전에서는 분명히)은 netmodule 참조를 추가 할 수 없기 때문에 디버깅 할 때 두 개의 별도 어셈블리에 두어야합니다. 어셈블리의 일부로 추가 할 수있는 유일한 방법은 csc.exe를 직접 실행하는 것입니다./addmodule:{files}
명령 행 인수. 그것은 없을거야.너무고통스러운 MSBuild 스크립트. 물론, 용감하거나 바보 같은 사람이라면 매번 수동으로 csc를 실행할 수 있습니다. 또한 여러 어셈블리가 액세스해야하기 때문에 더욱 복잡해집니다.
그래서 .Net에서 할 수 있습니다. 그것은 여분의 노력의 가치가 있니? 음, 그걸 결정하게 내버려 두 겠네.
추가 크레딧 :enum
MSIL : F # 외에 적어도 하나 이상의 다른 .NET 언어에서도 가능합니다.
type MyThing =
static member GetEnumFromString<'T when 'T :> Enum> str defaultValue: 'T =
/// protect for null (only required in interop with C#)
let str = if isNull str then String.Empty else str
Enum.GetValues(typedefof<'T>)
|> Seq.cast<_>
|> Seq.tryFind(fun v -> String.Compare(v.ToString(), str.Trim(), true) = 0)
|> function Some x -> x | None -> defaultValue
이 도구는 Visual Studio IDE를 완벽하게 지원하는 잘 알려진 언어이므로 유지 관리가 더 쉽지만 솔루션에 별도의 프로젝트가 필요합니다. 그러나 자연스럽게 다른 IL을 생성합니다 (코드~이다.매우 다른).FSharp.Core
라이브러리는 다른 외부 라이브러리와 마찬가지로 배포본의 일부가되어야합니다.
여기서는 (MSIL 솔루션과 기본적으로) 동일한 방법으로 사용할 수 있으며, 동의어가있는 구조체에서 올바르게 실패했음을 보여줍니다.
// works, result is inferred to have type StringComparison
var result = MyThing.GetEnumFromString("OrdinalIgnoreCase", StringComparison.Ordinal);
// type restriction is recognized by C#, this fails at compile time
var result = MyThing.GetEnumFromString("OrdinalIgnoreCase", 42);
There's no particularly unusual reason why not; we have lots of other things to do, limited budgets, and this one has never made it past the "wouldn't this be nice?" discussion in the language design team.
- Christopher CurrensT
에System.Enum
모든 일을 할 수 없다면T
사람들이 기대할지도 모르는 C #의 저자들은 모두 그것을 금지 할 수 있다고 생각했습니다. 나는 그 결정이 불행하다고 생각한다. 왜냐하면 C #은 단순히 특별한 처리를 무시했다.System.Enum
제약 조건을 사용하면HasAnyFlags<T>(this T it, T other)
확장 방법은Enum.HasFlag(Enum)
인수를 유형 검사했다. - supercat
C # 7.3 (Visual Studio 2017 ≥ v15.7에서 사용 가능)부터이 코드는 이제 완전히 유효합니다.
public static TEnum Parse<TEnum>(string value)
where TEnum : struct, Enum { ... }
제약 상속을 남용하여 실제 컴파일러가 enum 제약을 적용 할 수 있습니다. 다음 코드는class
및struct
동시에 제약 조건 :
public abstract class EnumClassUtils<TClass>
where TClass : class
{
public static TEnum Parse<TEnum>(string value)
where TEnum : struct, TClass
{
return (TEnum) Enum.Parse(typeof(TEnum), value);
}
}
public class EnumUtils : EnumClassUtils<Enum>
{
}
용법:
EnumUtils.Parse<SomeEnum>("value");
참고 :이 내용은 C # 5.0 언어 사양에 명시되어 있습니다.
타입 파라미터 S가 타입 파라미터 T에 의존하는 경우, [...] S는 값 타입 제약을 가지며 T는 참조 타입을 갖는다. 강제. 효과적으로 이것은 T를 System.Object 유형으로 제한합니다. System.ValueType, System.Enum 및 모든 인터페이스 유형
EnumClassUtils<System.Enum>
T를 임의의 것으로 제한하기에 충분하다.System.Enum
및 파생 된 유형.struct
...에Parse
그런 다음 그것을 실제 enum 유형으로 더 제한합니다. 제한해야합니다.Enum
어떤 시점에서. 이렇게하려면 클래스를 중첩해야합니다. 만나다gist.github.com/MrJul/7da12f5f2d6c69f03d79 - Julien Lebosquainwhere TClass : class
제약 이득은 여기? - tsemer
편집하다
이제 질문은 다음과 같이 훌륭하게 답변되었습니다.줄리앙 레 보스 퀘인.
나는 또한 그의 대답을 연장하고 싶다.ignoreCase
,defaultValue
선택적 인수를 추가하는 동안TryParse
과ParseOrDefault
.
public abstract class ConstrainedEnumParser<TClass> where TClass : class
// value type constraint S ("TEnum") depends on reference type T ("TClass") [and on struct]
{
// internal constructor, to prevent this class from being inherited outside this code
internal ConstrainedEnumParser() {}
// Parse using pragmatic/adhoc hard cast:
// - struct + class = enum
// - 'guaranteed' call from derived <System.Enum>-constrained type EnumUtils
public static TEnum Parse<TEnum>(string value, bool ignoreCase = false) where TEnum : struct, TClass
{
return (TEnum)Enum.Parse(typeof(TEnum), value, ignoreCase);
}
public static bool TryParse<TEnum>(string value, out TEnum result, bool ignoreCase = false, TEnum defaultValue = default(TEnum)) where TEnum : struct, TClass // value type constraint S depending on T
{
var didParse = Enum.TryParse(value, ignoreCase, out result);
if (didParse == false)
{
result = defaultValue;
}
return didParse;
}
public static TEnum ParseOrDefault<TEnum>(string value, bool ignoreCase = false, TEnum defaultValue = default(TEnum)) where TEnum : struct, TClass // value type constraint S depending on T
{
if (string.IsNullOrEmpty(value)) { return defaultValue; }
TEnum result;
if (Enum.TryParse(value, ignoreCase, out result)) { return result; }
return defaultValue;
}
}
public class EnumUtils: ConstrainedEnumParser<System.Enum>
// reference type constraint to any <System.Enum>
{
// call to parse will then contain constraint to specific <System.Enum>-class
}
사용 예 :
WeekDay parsedDayOrArgumentException = EnumUtils.Parse<WeekDay>("monday", ignoreCase:true);
WeekDay parsedDayOrDefault;
bool didParse = EnumUtils.TryParse<WeekDay>("clubs", out parsedDayOrDefault, ignoreCase:true);
parsedDayOrDefault = EnumUtils.ParseOrDefault<WeekDay>("friday", ignoreCase:true, defaultValue:WeekDay.Sunday);
늙은
내 이전 개선 사항비벡의 대답의견 및 '새로운'개발을 사용하여 :
TEnum
사용자의 편의를 위해TryParse
핸들ignoreCase
기존 매개 변수로
(VS2010 / NET 4에서 소개)default
값(VS2005 / .Net 2에서 소개)defaultValue
과ignoreCase
를 야기하는:
public static class EnumUtils
{
public static TEnum ParseEnum<TEnum>(this string value,
bool ignoreCase = true,
TEnum defaultValue = default(TEnum))
where TEnum : struct, IComparable, IFormattable, IConvertible
{
if ( ! typeof(TEnum).IsEnum) { throw new ArgumentException("TEnum must be an enumerated type"); }
if (string.IsNullOrEmpty(value)) { return defaultValue; }
TEnum lResult;
if (Enum.TryParse(value, ignoreCase, out lResult)) { return lResult; }
return defaultValue;
}
}
T 유형이 열거 형인지 점검하고 그렇지 않은 경우 예외를 throw하는 클래스에 정적 생성자를 정의 할 수 있습니다. Jeffery Richter가 C #을 통해 저서 인 CLR에서 언급 한 방법입니다.
internal sealed class GenericTypeThatRequiresAnEnum<T> {
static GenericTypeThatRequiresAnEnum() {
if (!typeof(T).IsEnum) {
throw new ArgumentException("T must be an enumerated type");
}
}
}
그런 다음 구문 분석 메서드에서 Enum.Parse (typeof (T), input, true)를 사용하여 문자열에서 열거 형으로 변환 할 수 있습니다. 마지막 true 매개 변수는 입력의 대소 문자를 무시하기위한 것입니다.
Enum
T
생성자가 실행될 때. 이것은 인스턴스 생성자를 기다리는 것보다 훨씬 좋지만. - jrh
나는 샘플을 dimarzionist로 수정했다. 이 버전은 Enums에서만 작동하며 구조체를 통과시키지 않습니다.
public static T ParseEnum<T>(string enumString)
where T : struct // enum
{
if (String.IsNullOrEmpty(enumString) || !typeof(T).IsEnum)
throw new Exception("Type given must be an Enum");
try
{
return (T)Enum.Parse(typeof(T), enumString, true);
}
catch (Exception ex)
{
return default(T);
}
}
코드를 약간 개선하려고했습니다.
public T LoadEnum<T>(string value, T defaultValue = default(T)) where T : struct, IComparable, IFormattable, IConvertible
{
if (Enum.IsDefined(typeof(T), value))
{
return (T)Enum.Parse(typeof(T), value, true);
}
return defaultValue;
}
defaultValue.ToString("D", System.Globalization.NumberFormatInfo.CurrentInfo)
어떤 종류의 열거 형인지 알지 못하더라도 그 열거 형 만이 열거 형입니다. - styfleIsDefined
그래도 케이스의 무감각 함을 망칠 것입니다. 같지 않은Parse
,IsDefined
없다ignoreCase
논의,MSDN은 정확한 경우에만 일치한다고 말합니다.. - Nyerguds
또한 Enum 제약 조건을 사용하는 C # 7.3의 릴리스는 추가 검사 및 작업을 수행하지 않고도 즉시 사용할 수 있도록 지원됩니다.
앞으로도 C # 7.3으로 프로젝트의 언어 버전을 변경했다면 다음 코드가 완벽하게 작동합니다.
private static T GetEnumFromString<T>(string value, T defaultValue) where T : Enum
{
// Your code goes here...
}
언어 버전을 C # 7.3으로 변경하는 방법을 모르는 경우 다음 스크린 샷을 참조하십시오.
편집 1 - 필요한 Visual Studio 버전 및 ReSharper 고려
Visual Studio에서 새 구문을 인식하려면 최소한 버전 15.7이 필요합니다. Microsoft의 릴리스 정보에서도 언급 된 것을 볼 수 있습니다.Visual Studio 2017 15.7 릴리스 정보. 이 유효한 질문을 지적 해 주신 @MohamedElshawaf에게 감사드립니다.
Pls는 또한 필자의 경우 ReSharper 2018.1을 쓰는 시점에서이 EDIT가 아직 C # 7.3을 지원하지 않는다고 언급합니다. ReSharper를 활성화하면 Enum 제약 조건이 나에게 오류로 강조 표시됩니다.형식 매개 변수 제약 조건으로 'System.Array', 'System.Delegate', 'System.Enum', 'System.ValueType', 'object'를 사용할 수 없습니다.. ReSharper는 빠른 수정으로 제안합니다.메서드의 매개 변수 T의 'Enum'제약 조건 제거
그러나 ReSharper를 일시적으로 사용 중지 한 경우도구 -> 옵션 -> ReSharper Ultimate -> 일반VS 15.7 이상 및 C # 7.3 이상을 사용할 경우 문법이 완벽하게 괜찮음을 알 수 있습니다.
where T : struct, Enum
, 지나가는 것을 피하기 위해System.Enum
그 자체가 타입 파라미터로서. - Mariusz Pawelskistruct, Enum
. 내 근거는 해답과 설명에 설명되어 있습니다.이리. - Stephen Kennedy
enum 값과 관련된 텍스트와 함께 enum을 사용해야하는 특정 요구 사항이 있습니다. 예를 들어 enum을 사용하여 오류 유형을 지정하면 오류 세부 정보를 설명해야합니다.
public static class XmlEnumExtension
{
public static string ReadXmlEnumAttribute(this Enum value)
{
if (value == null) throw new ArgumentNullException("value");
var attribs = (XmlEnumAttribute[]) value.GetType().GetField(value.ToString()).GetCustomAttributes(typeof (XmlEnumAttribute), true);
return attribs.Length > 0 ? attribs[0].Name : value.ToString();
}
public static T ParseXmlEnumAttribute<T>(this string str)
{
foreach (T item in Enum.GetValues(typeof(T)))
{
var attribs = (XmlEnumAttribute[])item.GetType().GetField(item.ToString()).GetCustomAttributes(typeof(XmlEnumAttribute), true);
if(attribs.Length > 0 && attribs[0].Name.Equals(str)) return item;
}
return (T)Enum.Parse(typeof(T), str, true);
}
}
public enum MyEnum
{
[XmlEnum("First Value")]
One,
[XmlEnum("Second Value")]
Two,
Three
}
static void Main()
{
// Parsing from XmlEnum attribute
var str = "Second Value";
var me = str.ParseXmlEnumAttribute<MyEnum>();
System.Console.WriteLine(me.ReadXmlEnumAttribute());
// Parsing without XmlEnum
str = "Three";
me = str.ParseXmlEnumAttribute<MyEnum>();
System.Console.WriteLine(me.ReadXmlEnumAttribute());
me = MyEnum.One;
System.Console.WriteLine(me.ReadXmlEnumAttribute());
}
희망이 도움이 :
public static TValue ParseEnum<TValue>(string value, TValue defaultValue)
where TValue : struct // enum
{
try
{
if (String.IsNullOrEmpty(value))
return defaultValue;
return (TValue)Enum.Parse(typeof (TValue), value);
}
catch(Exception ex)
{
return defaultValue;
}
}
return (TValue)Enum.Parse(typeof (TValue), value);
으로return (TValue)Enum.Parse(typeof (TValue), value, true);
- Paulo Santos
흥미롭게도, 이것은 분명히다른 언어에서 가능하다.(Managed C ++, IL 직접).
인용하기 :
... 두 제약 조건은 실제로 유효한 IL을 생성하며 다른 언어로 작성된 경우 C #에서 소비 할 수도 있습니다 (관리되는 C ++ 또는 IL에서 이러한 제약 조건을 선언 할 수 있음).
누가 알아
이것은 그것에 나의 포획이다. 답변과 MSDN의 결합
public static TEnum ParseToEnum<TEnum>(this string text) where TEnum : struct, IConvertible, IComparable, IFormattable
{
if (string.IsNullOrEmpty(text) || !typeof(TEnum).IsEnum)
throw new ArgumentException("TEnum must be an Enum type");
try
{
var enumValue = (TEnum)Enum.Parse(typeof(TEnum), text.Trim(), true);
return enumValue;
}
catch (Exception)
{
throw new ArgumentException(string.Format("{0} is not a member of the {1} enumeration.", text, typeof(TEnum).Name));
}
}
TEnum
실제로는 Enum 유형이지만text
빈 문자열입니다.ArgumentException
& quot; TEnum은 열거 형이어야합니다 & quot; 비록 그것이 그렇다고해도. - Nick
기존 답변은 C # ≤ 7.2에서 true입니다. 그러나 C # 언어가 있습니다.기능 요청(에 묶여corefx기능 요청)을 허용합니다;
public class MyGeneric<TEnum> where TEnum : System.Enum
{ }
글을 쓰는 시점에서이 기능은 언어 개발 회의 (Language Development Meetings)에서 "토론 중"입니다.
편집하다
나는 항상 이것을 좋아했다 (당신은 적절하게 수정할 수 있었다) :
public static IEnumerable<TEnum> GetEnumValues()
{
Type enumType = typeof(TEnum);
if(!enumType.IsEnum)
throw new ArgumentException("Type argument must be Enum type");
Array enumValues = Enum.GetValues(enumType);
return enumValues.Cast<TEnum>();
}
일리노이를 사용하는 Christopher Currens의 솔루션을 좋아했지만 MSIL을 자신의 빌드 프로세스에 포함시키는 까다로운 비즈니스를 처리하고 싶지 않은 사람들을 위해 C #에서 비슷한 기능을 썼습니다.
그래도 일반적인 제한을 사용할 수는 없지만where T : Enum
Enum은 특별한 타입이기 때문에. 따라서 주어진 generic 형식이 실제로 enum인지 확인해야합니다.
내 기능은 다음과 같습니다.
public static T GetEnumFromString<T>(string strValue, T defaultValue)
{
// Check if it realy enum at runtime
if (!typeof(T).IsEnum)
throw new ArgumentException("Method GetEnumFromString can be used with enums only");
if (!string.IsNullOrEmpty(strValue))
{
IEnumerator enumerator = Enum.GetValues(typeof(T)).GetEnumerator();
while (enumerator.MoveNext())
{
T temp = (T)enumerator.Current;
if (temp.ToString().ToLower().Equals(strValue.Trim().ToLower()))
return temp;
}
}
return defaultValue;
}
Vivek의 솔루션을 재사용 할 수있는 유틸리티 클래스에 캡슐화했습니다. 귀하의 유형에 "T : struct, IConvertible"형식 제약 조건을 정의해야합니다.
using System;
internal static class EnumEnforcer
{
/// <summary>
/// Makes sure that generic input parameter is of an enumerated type.
/// </summary>
/// <typeparam name="T">Type that should be checked.</typeparam>
/// <param name="typeParameterName">Name of the type parameter.</param>
/// <param name="methodName">Name of the method which accepted the parameter.</param>
public static void EnforceIsEnum<T>(string typeParameterName, string methodName)
where T : struct, IConvertible
{
if (!typeof(T).IsEnum)
{
string message = string.Format(
"Generic parameter {0} in {1} method forces an enumerated type. Make sure your type parameter {0} is an enum.",
typeParameterName,
methodName);
throw new ArgumentException(message);
}
}
/// <summary>
/// Makes sure that generic input parameter is of an enumerated type.
/// </summary>
/// <typeparam name="T">Type that should be checked.</typeparam>
/// <param name="typeParameterName">Name of the type parameter.</param>
/// <param name="methodName">Name of the method which accepted the parameter.</param>
/// <param name="inputParameterName">Name of the input parameter of this page.</param>
public static void EnforceIsEnum<T>(string typeParameterName, string methodName, string inputParameterName)
where T : struct, IConvertible
{
if (!typeof(T).IsEnum)
{
string message = string.Format(
"Generic parameter {0} in {1} method forces an enumerated type. Make sure your input parameter {2} is of correct type.",
typeParameterName,
methodName,
inputParameterName);
throw new ArgumentException(message);
}
}
/// <summary>
/// Makes sure that generic input parameter is of an enumerated type.
/// </summary>
/// <typeparam name="T">Type that should be checked.</typeparam>
/// <param name="exceptionMessage">Message to show in case T is not an enum.</param>
public static void EnforceIsEnum<T>(string exceptionMessage)
where T : struct, IConvertible
{
if (!typeof(T).IsEnum)
{
throw new ArgumentException(exceptionMessage);
}
}
}
확장 메서드를 만들었습니다.to get integer value from enum
메소드 구현을 살펴 본다.
public static int ToInt<T>(this T soure) where T : IConvertible//enum
{
if (typeof(T).IsEnum)
{
return (int) (IConvertible)soure;// the tricky part
}
//else
// throw new ArgumentException("T must be an enumerated type");
return soure.ToInt32(CultureInfo.CurrentCulture);
}
이것은 사용법이다.
MemberStatusEnum.Activated.ToInt()// using extension Method
(int) MemberStatusEnum.Activated //the ordinary way
이전에 다른 답변에서 언급 한 것처럼 이것은 소스 코드로 표현 될 수 없지만 IL 레벨에서 실제로 수행 될 수 있습니다. @Christopher Currens대답일리노이가 어떻게하는지 보여줍니다.
와사료s Add-InExtraConstraints.Fody이를 달성하기 위해 빌드 툴링으로 완성되는 아주 간단한 방법이 있습니다. 그냥 너겟 패키지를 추가하십시오 (Fody
,ExtraConstraints.Fody
)를 프로젝트에 추가하고 다음과 같이 제약 조건을 추가하십시오 (ExtraConstraints의 Readme에서 발췌 한 내용).
public void MethodWithEnumConstraint<[EnumConstraint] T>() {...}
public void MethodWithTypeEnumConstraint<[EnumConstraint(typeof(ConsoleColor))] T>() {...}
Fody는 제약이 존재하기 위해 필요한 일리노이를 추가 할 것입니다. 또한 대리자를 제한하는 추가 기능에 유의하십시오.
public void MethodWithDelegateConstraint<[DelegateConstraint] T> ()
{...}
public void MethodWithTypeDelegateConstraint<[DelegateConstraint(typeof(Func<int>))] T> ()
{...}
Enum에 관해서는 매우 흥미로운 것을 메모하고 싶을 수도 있습니다.Enums.NET.
나중에 직접 다이렉트 캐스팅을 사용해도 괜찮다면System.Enum
필요한 경우 기본 메소드를 사용하십시오. 형식 매개 변수를 신중하게 바꾸면됩니다. 따라서 메소드 구현은 다음과 같습니다.
public static class EnumUtils
{
public static Enum GetEnumFromString(string value, Enum defaultValue)
{
if (string.IsNullOrEmpty(value)) return defaultValue;
foreach (Enum item in Enum.GetValues(defaultValue.GetType()))
{
if (item.ToString().ToLower().Equals(value.Trim().ToLower())) return item;
}
return defaultValue;
}
}
다음과 같이 사용할 수 있습니다.
var parsedOutput = (YourEnum)EnumUtils.GetEnumFromString(someString, YourEnum.DefaultValue);
Enum.ToObject()
보다 유연한 결과를 얻을 수 있습니다. 추가 할 필요가없는 대소 문자 구분없이 문자열 비교를 수행 할 수 있습니다.ToLower()
- DiskJunky
자바에서는 다음을 사용합니다.
SomeClass<T extends enum> {
}
아주 간단합니다.