【问题标题】:c# How to map a string to a class in set of common classes via a static memberc#如何通过静态成员将字符串映射到一组公共类中的类
【发布时间】:2014-09-01 14:59:16
【问题描述】:

我需要根据一个字符串在一组类中找到一个类,我们称之为 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";
    
    }
    
  • 但我不知道如何强制派生类覆盖该字段!

  • 也研究了一下单例,但不确定这是否是正确的路径

也许我解决这种将动作映射到特定班级的思路是在错误的火车站:)

【问题讨论】:

  • 我认为属性,特别是类属性,更适合。因此,您可以使用 ActionString 使用您期望用户提供的一些字符串来注释类。
  • IMO 你走错路了。使用属性或在集中位置手动配置映射。你在追求自动化方面做得太过分了,你最终会得到可能更自动化的代码,但会有非常不受欢迎的属性(首先是“远距离行动”)。

标签: c# c#-4.0


【解决方案1】:

我认为 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 {
}

【讨论】:

    【解决方案2】:

    在界面中有一个枚举怎么样。而在实际的具体类构造函数中。设置特定于该类类型的枚举值。我认为您也可以使用任何其他类型的属性来做到这一点..

    【讨论】:

      【解决方案3】:

      不久前我做过类似的事情, 它看起来有点像这样:(我真的不确定那个代码,这可能需要一些编辑)

      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();
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-09-26
        • 2021-06-19
        • 2022-01-25
        • 1970-01-01
        • 2016-08-24
        • 1970-01-01
        相关资源
        最近更新 更多