0

我有一个从抽象超类继承的类家族,它由两个具体类实现:

public abstract class AbstractFoo 
{
    protected static string fooName = "Reset me!";

    public static string GetName()
    {
         return fooName;
    }
}

然后像这样构造子类

public class BarFoo : AbstractFoo 
{
    static BarFoo() 
    {
         fooName = "Pretty Name For BarFoo";
    }
}

等等。

我想获取所有AbstractFoo实现的漂亮名称的列表,以便用户可以决定使用哪个实现。

我的反射代码看起来像

 Type fooType = typeof(AbstractFoo);

 List<Assembly> assemblies = new List<Assembly>(AppDomain.CurrentDomain.GetAssemblies());

 IEnumerable<Type> allTypes = assemblies.SelectMany<Assembly, Type>(s => s.GetTypes());
 IEnumerable<Type> fooTypes = allTypes.Where(p => p.IsSubclassOf (fooType));

 foreach (Type thisType in fooTypes) 
 {
      MethodInfo method = thisType.GetMethod ("GetName", BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
      string name = (string) method.Invoke (null, null);
  // add to the list, anyhow names.Add (name);  
  }

我最终method.Invoke总是返回“重命名我”而不是个人名称。

我很确定我在这里做了一些愚蠢的事情,但我不太确定是什么。

4

2 回答 2

4

你有两个问题。

首先,你的静态字段真的不会做你想做的事。有一个静态字段,在AbstractFoo- 没有单独的BarFoo.fooName静态字段。因此,如果您有一堆子类,那么最后一个类型初始化的子类将在设置字段时“获胜”。

接下来,当您调用 时BarFoo.GetName,这实际上只是对AbstractFoo.GetName-的调用,BarFoo不会被初始化,因此您不会看到设置了“漂亮名称”。

从根本上说,我建议你重新设计你的代码。我建议你用一个属性来装饰每个类。这样一来,您根本不会依赖类型初始化程序,并且您不需要为每种类型声明单独的静态成员。唯一的缺点是该值必须是一个常数......

另一种方法是使用虚拟属性,然后在子类中覆盖该属性 - 当然,这需要您创建每种类型的实例。

于 2013-07-17T19:12:54.060 回答
2

静态成员有一份副本。使用您当前的设置,每个子类都将覆盖该副本,导致只有一个名称可用。您需要在每个子类上创建一个静态 GetName 函数,然后直接返回名称。我会推荐一些类似的东西:

public abstract class AbstractFoo
{
}

public class BarFoo : AbstractFoo 
{
    public static string GetName()
    {
        return "Pretty Name For BarFoo";
    }
}

 Type fooType = typeof(AbstractFoo);
 List<Assembly> assemblies = new List<Assembly>(AppDomain.CurrentDomain.GetAssemblies());
 IEnumerable<Type> allTypes = assemblies.SelectMany<Assembly, Type>(s => s.GetTypes());
 IEnumerable<Type> fooTypes = allTypes.Where(p => p.IsSubclassOf (fooType));
 foreach (Type thisType in fooTypes) 
 {

      MethodInfo method = thisType.GetMethod ("GetName", BindingFlags.Public | BindingFlags.Static);
      string name = (string) method.Invoke (null, null);
  // add to the list, anyhow names.Add (name);  
  }

另一种方法是将 aDictionary作为静态成员保留,AbstractFoo并让子类的静态初始化程序向该字典添加一些内容。

于 2013-07-17T19:12:38.690 回答