What is the type of element (of a collection) which retrieve from using Activator.CreateInstance method?

46 Views Asked by At

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~

1

There are 1 best solutions below

2
On BEST ANSWER

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.