2014-12-11 2 views
0

잠재적으로 여러 필드와 메서드가 포함 된 사용자 지정 enum 클래스를 만들기 위해 파생 될 수있는 기본 클래스를 만들려고합니다. 기본 클래스는 각 enum 유형에 대해 정의 된 모든 값 목록과 모든 값에 대한 이름 변수 목록을 유지합니다. 내가 겪고있는 문제는 CLR의 동작으로 인해 직접 클래스 중 하나를 호출 할 때까지 클래스를 파생시키는 정적 필드가 초기화되지 않지만 정의 된 목록에 자신을 추가하기 위해 초기화해야한다는 것입니다. 그 열거 형의 값. 내가 이전에 같은 짓을하지 않는 한파생 클래스의 정적 필드가 기본 클래스에서 필요하기 전에 초기화되지 않았습니다.

예를 들어, 수집 Day.Values이 비어있을 것입니다 :

일 오늘 = Day.MONDAY;

먼저 필드 중 하나를 호출하지 않아도 Day.Values를 호출하면 Day의 정적 필드가 초기화되도록하는 방법이 있습니까? 또는이 기능을 구현하는 더 좋은 방법이 있습니까?

public abstract class EnumBase<T> where T : EnumBase<T> 
{ 
    private static List<T> values = new List<T>(); 
    public static ReadOnlyCollection<T> Values 
    { 
     get 
     { 
      return values.AsReadOnly(); 
     } 
    } 

    public string name { get; private set; } 

    protected EnumBase(string name) 
    { 
     this.name = name; 
     values.Add((T)this); 
    } 

    public override string ToString() 
    { 
     return this.name; 
    } 
} 

public class Day : EnumBase<Day> 
{ 
    public static readonly Day MONDAY = new Day("monday"); 
    public static readonly Day TUESDAY = new Day("tuesday"); 
    //... 

    private Day (string name) : base (name) 
    { 

    } 
} 
+0

달성하고자하는 것이 무엇인지 정확히 설명 할 수 있습니까? 나는 당신의 코드에서 언제 어디서나 'Day.Values'를 사용하거나 추가하지 않고'Day today = Day.MONDAY'가'Day.Values'에서 어떤 것을 변경시킬 것이라고 생각하지 않습니다. ' – Saggio

+0

물론 기본 클래스의 지휘자에서 파생 클래스의 데이터를 사용할 수 없습니다. 가능한 최선의 방법은 원하는 데이터를 초기화하는 파생 클래스의 생성자에서 기본 클래스의 메서드를 호출하는 것입니다. –

+0

@Saggio'MONDAY' 또는'TUESDAY'가 생성 될 때, protected EnumBase 생성자를 시작하고 값 컬렉션에 자신을 추가합니다. 편집 - 아니면 '해야'라고 말해야합니까? – impr0t

답변

0

리플렉션을 사용하여 관련 필드에 대해 파생 된 유형을 검사 할 수 있습니다.

또한 Values에 처음 액세스 할 때이 초기화 작업을 수행하고 필요할 때까지이 작업을 연기하고 결과를 캐싱 할 수 있습니다. 이러한 동의어이기 때문에,

public abstract class EnumBase<T> where T : EnumBase<T> 
{ 
    static Lazy<List<T>> values = new Lazy<List<T>>(FindEnumMembers); 
    public static IEnumerable<T> Values 
    { 
     get 
     { 
      return values.Value; 
     } 
    } 

    static List<T> FindEnumMembers() 
    { 
     Type derivedType = typeof(T); 
     return derivedType.GetFields() 
          .Where(f => f.FieldType == derivedType) 
          .Select(f => (T)f.GetValue(null)) 
          .ToList(); 
    } 

    public string name { get; private set; } 

    protected EnumBase(string name) 
    { 
     this.name = name; 
    } 

    public override string ToString() 
    { 
     return this.name; 
    } 
} 

public class Day : EnumBase<Day> 
{ 
    public static readonly Day MONDAY = new Day("monday"); 
    public static readonly Day TUESDAY = new Day("tuesday"); 
    //... 

    private Day (string name) : base (name) 
    { 

    } 
} 

액세스 중 하나의 방법을 작동합니다 : 이러한 동의어 다시

Day.Values 
//or// 
EnumBase<Day>.Values 

참고이 원래의 근본 원인이기 때문에 여기에

은 예입니다 문제. Day.Values을 호출하는 것은 실제로 EnumBase<Day>.Values으로 해석되므로 다른 유형의 정적 멤버 Day은이 호출로 초기화되지 않습니다. EnumBase<T>에 리플렉션을 사용하고 파생 형식의 필드를 요청하면 정적으로 해당 지점에 액세스 한 것처럼 GetValue 호출의 부작용으로 초기화됩니다 (아직 완료되지 않은 경우).

0

나는 이것을 테스트 할 시간이 없었지만, 여기에 각 열거 형 클래스를 싱글 톤으로 갖는 예가있다. (나는 그것이 효과가 있기를 바란다.) : D

클래스의 다른 확장이 실수로 데이터를 공유하지 않도록 기본 클래스에서 정적을 꺼내서 "Day"단일체에 추가했다.

싱글 톤은 어디서나 호출 할 수 있으며 자신의 인스턴스 하나를 만들 수 있습니다.

Day.method(); // From anywhere 

Day.addEnum ('수요일');

public abstract class EnumBase<T> where T : EnumBase<T> 
{ 
    private List<T> values = new List<T>(); 
    public ReadOnlyCollection<T> Values 
    { 
     get 
     { 
      return values.AsReadOnly(); 
     } 
    } 

    public string name { get; private set; } 

    protected EnumBase() 
    { 

    } 

    public string addEnum() 
    { 
     this.name = name; 
     values.Add((T)this); 
    } 

    public override string ToString() 
    { 
     return this.name; 
    } 
} 

using System; 

public class Day : EnumBase<Day> 
{ 
    private static Day instance; 
    private Day() {} 

    public static Day Instance 
    { 
     get 
     { 
      if (instance == null) 
      { 
       instance = new Day(); 
      } 
      return instance; 
     } 
    } 
    addEnum('monday'); 
    addEnum('tuesday'); 
} 
관련 문제