#c_sharp #net #design #рефлексия
класс Building используется как более гибкая альтернатива Enum'ам (Type safe enum pattern ). Хотелось бы иметь возможность просматривать доступные статические поля в рантайме. В моем решении каждый такой класс должен будет однообразно реализовать статический метод GetAllFields() , что мне не особо нравится. Есть ли более элегантное решение данной проблемы , чем мое? public abstract class ABase { protected static IEnumerableGetAllField(Type type) { var res = from x in type.GetFields() where x.IsStatic == true where x.IsPublic == true select x.GetValue(null); ABase obj; foreach(var item in res) { if(!(item is ABase)) continue; obj = item as ABase; yield return obj; } } } public sealed class Building : ABase { public static readonly Building House = new Building(); public static readonly Building Castle = new Building(); public static System.Collections.Generic.IEnumerable GetAllFields() { return GetAllField(typeof(Building)); } }
Ответы
Ответ 1
Попробуйте так: public abstract class ABase { public IEnumerableGetAllFields() { return GetType().GetFields(BindingFlags.Static) .Select(fi => fi.GetValue(null)) .Where(f => f is ABase) .Cast (); } } Для статического метода трюк не сработает :( Ответ 2
Я бы решил эту задачу таким образом: public abstract class ABase { protected static IEnumerableGetAllField () => typeof(T) .GetFields(BindingFlags.Static | BindingFlags.Public) .Select(x => x.GetValue(null)) .OfType (); public string Name { get; protected set; } } public sealed class Building : ABase { public static readonly Building House = new Building(nameof(House)); public static readonly Building Castle = new Building(nameof(Castle)); private Building(string name) { Name = name; } public static IEnumerable GetAllFields() => GetAllField (); } Вы можете обойтись без свойства Name в ABase, тогда метод GetAllField может возвращать IEnumerable для Вашего примера в комментариях. А в моем примеры Вы можете проходить коллекию так: foreach (var item in Building.GetAllFields()) { Console.WriteLine(item.Name); // Ваша логика. } UPD: Можно автоматизировать создание read only полей, например так: public abstract class ABase { protected static IEnumerable GetAllField () => typeof(T) .GetFields(BindingFlags.Static | BindingFlags.Public) .Select(x => x.GetValue(null)) .OfType (); protected static void Init () => typeof(T) .GetFields(BindingFlags.Static | BindingFlags.Public) .ToList() .ForEach(x => x.SetValue(null, Activator.CreateInstance(typeof(T), x.Name))); public string Name { get; protected set; } } public sealed class Building : ABase { public static readonly Building House; public static readonly Building Castle; public Building(string name) { Name = name; } static Building() { Init (); } public static IEnumerable GetAllFields() => GetAllField (); } Но не могу не согласить с VladD что лучше перейти к instance-методам.
Комментариев нет:
Отправить комментарий