2011-09-22 6 views
4
나는 주위 검색

를 열거하고이 일을 예제를 찾을 수 없습니다 : Create Generic method constraining T to an Enum일반 T는,

가 내가있는 기능을 래핑하는 일반적인 기능을 가지고 API (나는 만질 수 없다). 래핑 된 함수는 System.Enum을 사용하여 동일한 값을 반환합니다. 제네릭 버전은이 예제의 훼손되지 않은 버전에서 작업을 상당히 단순화합니다.

T는 System.Enum에 제약이 없기 때문에 T부터 System.Enum 또는 T에 대문자를 사용할 수 없습니다. 적어도 내 이해입니다.

다음 코드는 작동하지만 내가 제네릭에 아주 새로운 오전 있기 때문에 나는 숨겨진 함정, 또는 더 나은 방법이 있는지 알고 궁금 :이 정상이라면

using System 
using System.Collections.Generic 
... 

    public T EnumWrapper<T>(T enumVar) where T : struct, IFormattable, IConvertible, IComparable 
    { 
     if (!typeof(T).IsEnum) 
      throw new ArgumentException("Generic Type must be a System.Enum") 

     // Use string parsing to get to an Enum and back out again 
     Enum e = (Enum)Enum.Parse(typeof(T), enumVar.ToString()); 
     e = WrappedFunction(e); 
     return (T)Enum.Parse(typeof(T), e.ToString()); 
    } 

가, 다음이 역할을 할 수 보기. 나는 이것을 발견 할 수 없었고, 최소한 그것이 작동하는 해결 방법이었다.

P. 성능은이 경우 문제가되지 않습니다. 나는 문자열 작업이 느릴 수도 있고 항상 성능 팁에 관심이 있다고 생각했다.

+0

추가 IFormattable과에서 IComparable (감사 @Michael B) : http://stackoverflow.com/questions/7508455/generic-t-with-enum-and-casting-t-to-enum/7516220#7516220 – Rafe

답변

4

더 엄격하게 만들 수 있습니다. 모든 enum은 followable 인터페이스 인 IFormattable, IConvertibleIComparable을 구현합니다. 이렇게하면 기본 클래스와 열거 형 클래스와 같이 작동하는 클래스로 제한됩니다.

또는, 당신은 정말 다음을 수행 할 수 있습니다를 열거에만 바인딩하는 방법 또는 클래스를 만들려면 :

public abstract class InvokerHelper<T> where T : class 
    { 
     public abstract R Invoke<R>(R value) where R : struct,T; 
    } 


     public class EnumInvoker : InvokerHelper<Enum> 
     { 
      public override R Invoke<R>(R value) 
      { 
       return (R)WrappedMethod(value); 
      } 
     } 

그 어설픈 및 확장 방법을 사용할 수 없습니다,하지만 당신이 만들 수 싱글 톤 객체를 생성 한 다음 일반 메소드 만 가질 수 있습니다.

또는, 당신은 당신이 where T:struct,Enum

실제로 방금 열거를 취하는 방법을 일반적인 T 호출을 할 나타나는 제약 조건을 가질 수 클래스를 만들 수 있습니다 귀하의 C++/CLI 코드 또는 Reflection.Emit를 작성할 수 및 그것을 T로 되 돌리는가?

그러면 다음이 작동합니다.

public static T WrappedMethodInvoker<T>(T value) where T:struct,IComparable,IFormattable,IConvertible 
{ 
    Enum e; 
    if((e = value as Enum) == null) 
     throw new ArgumentException("value must be an Enum") 
    object res = WrappedMethod(e); 
    return (T)res; 
} 

조금 더 쉽습니다. 먼저 T가 Enum이라는 것을 알고 as 연산자를 사용하여 null 유형 (참조 유형 또는 nullable struct)으로 캐스팅을 시도 할 수 있습니다. Enum이 가장 확실합니다. 거기에서 반환 유형의 공분산을 사용할 수 있습니다. WrappedMethodEnum을 반환합니다. 이는 객체에 저장할 수 있음을 의미합니다.마지막으로, 일반 메소드에 객체가있을 때 구문을 사용하여이를 T로 형변환 할 수 있습니다. 실패 할 수도 있지만 사실은 동일한 유형의 Enum을 반환합니다.

당신은 항상 복싱과 언 박싱을한다는 것을 아는 데 약간의 비용이 있습니다. 래핑 된 메서드는 일반적인 것입니까?

예제 사례에 맞게 수정 된 첫 번째 기술을 보여주는 답변을 편집했습니다. 매우 간단하고 유형 안전하지만 항상 작업을 수행하려면 EnumInvoker가 있어야합니다. 유감스럽게도 인수가 Enum 인 경우 WrappedMethod 상자 값을 호출 할 때 두 답변 모두 동일한 결과를 보여야합니다. 첫 번째 방법의 유일한 장점은 강력하게 형식화되어 있지만 일반적인 가상 메서드는 내가 아는 한 가장 느린 메서드입니다. 따라서 형식 검사를 피하면 코드를 호출하는 데 드는 비용이 들지 않을 수도 있습니다.

+0

@ Michawl B : 답변 해 주셔서 감사합니다. 교육 목적으로 확장 할 수 있습니까? 저는 C#으로 약간 초록색입니다. 제 배경은 파이썬, 자바 스크립트 등 CG 스크립팅에 더 많은 부분이 있습니다. 이 솔루션의 사용 샘플을 게시 할 수 있습니까? System.Enum (랩핑 된 함수로 /에서 전달)을 전달해야하는 제 상황에서 전달할 수 있고 전달 된 인수는 enum입니다 (API 내에서 실제로 작동하기 때문에 - 실제로 Unity 게임 엔진). – Rafe

+0

필요한 작업을 수행하는 간단한 방법을 추가했습니다. –

+0

나는 지난 제안을 사용하여 훌륭하게 작업했습니다. 그것은 문자열 핸드 오프보다 더 편안하다고 느낍니다. 네가 가진 유일한 오타는 던지기 라인 뒤에 누락 된 세미콜론이었습니다. 감사!! – Rafe

2

여기에서 문제는 간단합니다. C#의 유형 시스템에서는 열거 형에 제약 조건을 지정할 수 없습니다. 이 코드에는 명백한 함정이 없으며, Enum이 아닌 IConvertible 구조체를 전달하면 컴파일 타임 오류가 발생하지 않습니다. 이 경우 런타임에는 실패하지만 바람직하지는 않지만 더 좋은 옵션은 없습니다.

CodeContracts에 대해서는 아직 알지 못하지만 (CodeContracts에 대해서는 충분히 알지 못하지만) 여기에 확실한 대답을하기 위해 컴파일 타임에 CodeContracts를 사용하여이를 적용 할 수도 있습니다.

관련 문제