Мне нужно найти класс в наборе классов на основе строки, давайте назовем его ActionString (исходя из URL-адреса, введенного пользователем, который не равен имени класса!), Создайте экземпляр этого класса и вызовите метод класса TriggerSomeAction().
Поэтому каждый ActionString ("apple", "banana",...) должен отображаться в другом классе.
Чтобы код вроде
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();
даст мне правильный экземпляр и вызовет определенное действие.
Моя проблема
до сих пор я обнаружил, что
если я получаю классы из абстрактного класса, я могу указать статическое поле в этом базовом классе, например
public abstract class CommonBaseClass
{
public static string urlActionString;
}
and override it as
class ActionClass : CommonBaseClass
{
public static new string urlActionString = "apple";
}
но я не знаю, как бы заставить производный класс переопределить это поле!
Может быть, мой ход мыслей, чтобы решить это сопоставление действий конкретному классу, находится в неправильной железнодорожной станции :)
Я думаю, что класс 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 {
}
Я сделал что-то подобное не так давно, и это выглядело примерно так: (я действительно не уверен в этом коде, это может потребовать редактирования)
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();
}
Как насчет наличия Enum в интерфейсе. И в конкретном конкретном конструкторе класса. установите значение перечисления, соответствующее этому типу класса. Я думаю, вы можете сделать это с любым другим типом имущества тоже..