0

I have a case which is very similar to the case below:

Get all inherited classes of an abstract class

I have two classes which inherited to a base class

this is my base class:

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

And this is the first inhertied class:

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

second:

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

And I want to get the value of ModuleName: "FilmMusic" and "MovieStaffInfo".

With the value, before user entering the main form, I could add a new UI (UI for FilmMusic Module and another UI for MovieStaff) to the main form.

And below were the codes I have used (most referred to the case I have mentioned above):

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

And I got the output "null, null"

And I added those codes inside the foreach loop:

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

I have got what I want "FilmMusic, MovieStaffInfo".

I am a little bit confuse, what the elements inside the exporters collection ?

At first, I guess the item is an instantiation of class Module1, Module2...,therefore I could use item.ModuleName to access the value of ModuleName.

Actually, I can't, I have to use FieldInfo and GetValue to access the field value, but it is also strange, because using GetValue I have to create an instantiation first as a parameter assign to GetValue (in my case, the item is an instantiation of class Module1,Module2... I guess).

So, are the items of the collection exporters an instantiation of class Module1, Module2 or not?

If they are, why I got null when using item.ModuleName ?

Thanks for any opinion~

Kuo-hsuan Hsu
  • 677
  • 1
  • 6
  • 12
  • Why do you think you need a the `new` modifier for your fields? I am pretty sure they cause the trouble here. – thehennyy Nov 27 '18 at 06:51
  • I have tried remove the `new` from `new public string ModuleName = "FilmMusic"` and `new public string ModuleName = "MovieStaffInfo`; but I still got null when output. – Kuo-hsuan Hsu Nov 27 '18 at 06:56
  • 1
    That still hides the original member in the base class. Set your values using the constructor. Redeclaring the field means there are two complete independant fields now: `InputModule.ModuleName` and `Module1.ModuleName`. – thehennyy Nov 27 '18 at 06:58
  • Thanks to the explanation, it helps. – Kuo-hsuan Hsu Nov 27 '18 at 13:29

1 Answers1

1

You've defined ModuleName with the new keyword (e.g. new public string ModuleName). This means that if the variable pointing at the instance is typed as the base class, it won't be able to see the "new" field.

If you want to be able to see the module names, you have two options.

  1. Get rid of the new keyword. Instead, declare the member as an override, e.g.

    public override string ModuleName = "etc."; 
    
  2. Use reflection to invoke the field on the derived type, e.g.

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

See also Difference between new and overrride

Personally I recommend the first option. It is unusual to need the new keyword.

John Wu
  • 50,556
  • 8
  • 44
  • 80
  • Not redeclaring the field and just set its value in the constructor is also an option. – thehennyy Nov 27 '18 at 07:36
  • Thanks, I see. The `item` indeed is an instance of Module1, Module2... Therefore I could use `item` to get the value of field `ModuleName` by `GetValue`. The reason that I got null when using `item.ModuleName`, because it refers to the ModuleName of base class, and the value is null. – Kuo-hsuan Hsu Nov 27 '18 at 13:27