-2

I have a Model-Class that extends a BaseModel-class.

public abstract class BaseModel {
   public abstract string Name;
   public abstract string NamePlural;
   //....
}

public class Production : BaseModel
{
   public string Name = "production";
   public string NamePlural = "productions";
   //....
}

Somewhere else I call another class that uses the BaseModel as base for generics:

public class Store {
    public BaseModel SomeMethod<T>()
        where T : BaseModel
    {
         // here I need to get the Name property and the NamePlural property
         T.NamePlural; // gives compile error "T Not valid in the given context

         // next try:
         var model = typeof(T);
         model.NamePlural; // simply doesn't exist (model.Name gives the name of the class, but not the property)

         // another strange try:
         BaseModel model = new T(); // haha....nope

         //....
         return something...;
    }
}

//usage:

Store store = new Store();
Production p = SomeMethod<Production>();

So the question is:
Is there a simple way to access these properties?
I even tried via Assembly.GetTypes()..., ...

Or do I need another genreric class as described in those answers: How to access Property of generic member in generic class ?

Yes, I've read related questions Access to properties of generic object and Get property of generic class

Jeff
  • 6,895
  • 1
  • 15
  • 33
  • 1
    What do you mean by "get the Name property" - Do you mean the PropertyInfo reflection metadata? There is no object instance passed into the method? ... – Sam Jul 02 '18 at 22:13
  • What exactly do you mean "get the `NamePlural` property"? what do you need to do with it? – rossipedia Jul 02 '18 at 22:18
  • 2
    1) Your subclass properties aren't `override` so it's not doing what you think it's doing. 2) Are `Name` and `NamePlural` supposed to be static or something? You have no object to work with so it's very confusing. Please create a [mcve]. – itsme86 Jul 02 '18 at 22:19
  • Assume that your code does not need to be generic, how would you write it? As mentioned in another comment, where is the object of type T on which you want to call a method? – Phil1970 Jul 02 '18 at 22:20
  • 2
    A field cannot be abstract. `T` is a type, not an object. You need an object to access a non-static member. – Olivier Jacot-Descombes Jul 02 '18 at 22:21
  • Reading a book and learning the langage won't hurt. Tryin g things without understanding them will lead to poor code. – Phil1970 Jul 02 '18 at 22:22
  • @rossipedia I need it, because the RestApi is returning a json with the NamePlural as key. – Jeff Jul 02 '18 at 23:16
  • @itsme86 Thanks for the override hint. Yes, this might be a problem, but overriding doesn't really solve my other problem, does it? – Jeff Jul 02 '18 at 23:18
  • @Phil1970 well, yes, I'm trying to understand. This is why I ask questions... – Jeff Jul 02 '18 at 23:19
  • @OlivierJacot-Descombes _"You need an object to access a non-static member"_ totally makes sense, thanks! – Jeff Jul 02 '18 at 23:26

1 Answers1

4

The base model should have properties, not fields.

public abstract class BaseModel {
   public abstract string Name { get; }
   public abstract string NamePlural { get; }
   //....
}

You must override the abstract methods to implement them.

public class Production : BaseModel
{
   public override string Name => "production";
   // Same as:  public override string Name { get { return "production"; } }

   public override string NamePlural => "productions";
   //....
}

Pass an object to SomeMethod:

public class Store {
    public BaseModel SomeMethod<T>(T model)
        where T : BaseModel
    {
        string name = model.Name;
        string namePlural = model.NamePlural;
        ...
    }
}

Solely to access the names, no generic type parameters are required, since Production and other derived classes inherit the names. You can still pass the method a production object as argument:

public class Store {
    public BaseModel SomeMethod(BaseModel model)
    {
        string name = model.Name;
        string namePlural = model.NamePlural;
        ...
    }
}

If you want to use new on a generic type parameter, add the new constraint. This forces the type T to have a default constructor, i.e. a constructor with no parameters:

public BaseModel SomeMethod<T>()
    where T : BaseModel, new
{
    var model = new T();
    string name = model.Name;
    ...
}

If you want to give Production a static behavior, you can make it a singleton. On a type name or generic type name you can only access static members. Since static members cannot be abstract and cannot be inherited, the singleton pattern is the way to go if you want inheritance as well as a static behavior.

public class Production : BaseModel
{
    public static readonly Production Instance = new Production();

    private Production() // makes it non-instantiatable form outside.
    { }

    ...
}

You would use like this

store.SomeMethod(Production.Instance);
Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188