【问题标题】:What is the type of element (of a collection) which retrieve from using Activator.CreateInstance method?使用 Activator.CreateInstance 方法检索的(集合的)元素类型是什么?
【发布时间】:2019-04-28 20:44:37
【问题描述】:

我有一个案例和下面的案例非常相似:

Get all inherited classes of an abstract class

我有两个继承到基类的类

这是我的基类:

public abstract class InputModule
{
      public string ModuleName;
      public int NumberOfInputFields;
}

这是第一个继承的类:

public class Module1 : InputModule
{
      new public string  ModuleName = "FilmMusic";
      public new int NumberOfInputFields = 7;
}

秒:

public class Module2 : InputModule
{
      new public string ModuleName = "MovieStaffInfo";
      public new int NumberOfInputFields = 4;
}

我想获取 ModuleName 的值:“FilmMusic”和“MovieStaffInfo”。

有了这个值,在用户进入主窗体之前,我可以在主窗体中添加一个新的 UI(FilmMusic Module 的 UI 和 MovieStaff 的另一个 UI)。

以下是我使用的代码(最常提到我上面提到的案例):

public void detectTotalNumberOfSector()
{
     IEnumerable<InputModule> exporters = typeof(InputModule).Assembly.GetTypes().Where(t => t.IsSubclassOf(typeof(InputModule)) && !t.IsAbstract).Select(t => (InputModule)Activator.CreateInstance(t));
     foreach (var item in exporters)
     {
         Console.WriteLine(item.ModuleName);   
     } 
}

我得到了输出“null, null”

我在 foreach 循环中添加了这些代码:

FieldInfo info = item.GetType().GetField("ModuleName"); 
Console.WriteLine(info.GetValue(item));

我得到了我想要的“FilmMusic, MovieStaffInfo”。

我有点迷惑,exporters 集合里面的元素是什么?

起初,我猜item 是类Module1Module2...的实例化,因此我可以使用item.ModuleName 来访问ModuleName 的值。

其实我不能,我必须使用FieldInfoGetValue来访问字段值,但这也很奇怪,因为使用GetValue我必须先创建一个实例化作为参数分配给GetValue(在我的例子中,item 是类 Module1,Module2... 我猜的实例化)。

那么,集合导出器的项目是否是类 Module1、Module2 的实例化?

如果是,为什么我在使用 item.ModuleName 时得到 null ?

感谢大家的意见~

【问题讨论】:

  • 为什么您认为您的字段需要new 修饰符?我很确定他们在这里造成了麻烦。
  • 我已尝试从new public string ModuleName = "FilmMusic"new public string ModuleName = "MovieStaffInfo 中删除new;但输出时我仍然为空。
  • 这仍然隐藏了基类中的原始成员。使用构造函数设置您的值。重新声明该字段意味着现在有两个完整的独立字段:InputModule.ModuleNameModule1.ModuleName
  • 感谢解释,它有帮助。

标签: c# .net reflection createinstance fieldinfo


【解决方案1】:

您已经使用 new 关键字定义了 ModuleName(例如 new public string ModuleName)。这意味着如果将指向实例的变量键入为基类,它将无法看到“新”字段。

如果您希望能够看到模块名称,您有两种选择。

  1. 去掉new 关键字。相反,将成员声明为覆盖,例如

    public override string ModuleName = "etc."; 
    
  2. 使用反射来调用派生类型上的字段,例如

    Console.WriteLine
    (
        item.GetType()
            .GetField("ModuleName", BindingFlags.Instance | BindingFlags.Public)
            .GetValue(item)
    );
    

另见Difference between new and overrride

我个人推荐第一个选项。需要new 关键字并不常见。

【讨论】:

  • 不重新声明该字段而只在构造函数中设置其值也是一种选择。
  • 谢谢,我明白了。 item 确实是 Module1、Module2 的一个实例......因此我可以使用 item 通过 GetValue 获取字段 ModuleName 的值。我使用item.ModuleName时得到null的原因,因为它引用了基类的ModuleName,值为null。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-02-01
  • 2011-03-21
  • 2013-03-05
  • 1970-01-01
  • 2014-04-11
  • 1970-01-01
  • 2021-02-18
相关资源
最近更新 更多