c # Как сопоставить строку с классом в наборе общих классов через статический член

1

Мне нужно найти класс в наборе классов на основе строки, давайте назовем его ActionString (исходя из URL-адреса, введенного пользователем, который не равен имени класса!), Создайте экземпляр этого класса и вызовите метод класса TriggerSomeAction().

Поэтому каждый ActionString ("apple", "banana",...) должен отображаться в другом классе.

  • Каждый из этих классов должен основываться на общем базовом классе (например, CommonBaseClass) или реализовывать общий интерфейс (например, ICommonInterface) для определения некоторых общих членов. 1. чтобы я мог получить список всех подходящих классов через отражение и 2. быть расширяемым в будущем.
  • Я хотел, чтобы ActionString хранился как статический член в этих классах, поэтому я могу найти нужный класс без необходимости создавать экземпляр объекта всех классов.

Чтобы код вроде

var instance = from t in Assembly.GetExecutingAssembly().GetTypes()
                where t.GetInterfaces().Contains(typeof(ICommonInterface))
                        && t.ActionString = ActionStringEnteredByTheUser
                select Activator.CreateInstance(t) as ICommonInterface;
instance.TriggerSomeAction();

ИЛИ

var instance = from t in Assembly.GetExecutingAssembly().GetTypes()
                where t.IsSubclassOf(typeof(CommonBaseClass))
                        && t.ActionString = ActionStringEnteredByTheUser
                 select Activator.CreateInstance(t) as CommonBaseClass;
instance.TriggerSomeAction();

даст мне правильный экземпляр и вызовет определенное действие.

Моя проблема

  • Я хочу, чтобы все эти классы просто определяли ActionString, с которым я могу сравнивать (лучше, если постоянный, статический член и уникальный). Было бы здорово построить словарь, в котором ActionString является ключом, а классы - значением.

до сих пор я обнаружил, что

  • его невозможно заставить класс реализовать статический член через интерфейс и
  • поле const в интерфейсе уже должно иметь значение и
  • если я получаю классы из абстрактного класса, я могу указать статическое поле в этом базовом классе, например

    public abstract class CommonBaseClass
    {       
        public static string urlActionString;
    }
    
    and override it as
    
    class ActionClass : CommonBaseClass
    {
        public static new string urlActionString = "apple";
    
    }
    
  • но я не знаю, как бы заставить производный класс переопределить это поле!

  • также немного посмотрел на Синглтонов, но не уверен, что это правильный путь

Может быть, мой ход мыслей, чтобы решить это сопоставление действий конкретному классу, находится в неправильной железнодорожной станции :)

  • 0
    Я думаю, что атрибуты, особенно атрибуты класса, лучше подходят. Таким образом, вы можете аннотировать класс строкой, которую вы ожидаете от пользователя, с помощью ActionString.
  • 0
    ИМО ты идешь не в ту сторону. Используйте атрибут или настройте сопоставление вручную в централизованном месте. Вы зашли слишком далеко в своем стремлении автоматизировать вещи, и в итоге вы получите код, который может быть более автоматизированным, но будет иметь крайне нежелательные свойства (прежде всего, «действие на расстоянии»).
Теги:
c#-4.0

3 ответа

2
Лучший ответ

Я думаю, что класс Attribute - это то, что вы ищете. Простой пример:

Класс MarkerAttribute:

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public sealed class MarkerAttribute : Attribute {
  public string UrlAction { get; private set; }
  public MarkerAttribute(string urlAction) {
    if (string.IsNullOrEmpty(urlAction)) {
      throw new ArgumentNullException("urlAction");
    }
    UrlAction = urlAction;
  }
}

Некоторые классы по умолчанию:

[Marker("apple")]
public class Foo1 {
}

[Marker("banana")]
public class Foo2 {
}

Код для создания словаря типов в сборке:

var typeDictionary = 
  (from t in Assembly.GetExecutingAssembly().GetTypes()
   where t.GetCustomAttributes(typeof(MarkerAttribute), true) != null && 
         t.GetCustomAttributes(typeof(MarkerAttribute), true).Length > 0
   select new {
     Type = t,
     Action = ((MarkerAttribute)t.GetCustomAttributes(typeof(MarkerAttribute), true)[0]).UrlAction
 }).ToDictionary(k => k.Type, v => v.Action);

Что касается наследования:

// now the typeDictionary will contain { "banana", typeof(Foo3) } entry
public class Foo3 : Foo2 {
}

// now the typeDictionary will contain { "orange", typeof(Foo3) } entry
[Marker("orange")]
public class Foo3 : Foo2 {
}
0

Я сделал что-то подобное не так давно, и это выглядело примерно так: (я действительно не уверен в этом коде, это может потребовать редактирования)

public static void GetClass<T>(string ActionString) where  T : ICommonInterface, new()
{

   var c = Assembly.GetExecutingAssembly().GetTypes().Where(t => t.IsClass && t.BaseType == typeof(ICommonInterface)).First();
        FieldInfo de = c.GetType().GetField(ActionString);
        var obj = (T)de.GetValue(c);
        obj.TriggerSomeAction();
}
0

Как насчет наличия Enum в интерфейсе. И в конкретном конкретном конструкторе класса. установите значение перечисления, соответствующее этому типу класса. Я думаю, вы можете сделать это с любым другим типом имущества тоже..

Ещё вопросы

Сообщество Overcoder
Наверх
Меню