title: Get property value defined in an abstract class
body: <p>I'm working on a very simple framework, where I want to automate CRUD functions. For the purpose of this question, I've created the code below, simplified just to illustrate my issue(s).</p>
  
  <p>All items derive from the (abstract) base class "DbItem" (which contains the CRUD functions), whereby the child classes provide additional  functionality, and also define the table names where the DbItems are stored. For instance, "Equipment" and "Entity" both derive from DbItem, and define table names ("equipment" and "entities" respectively). However, "Entity" class is abstract and further derived by "Human" and "Animal" class. (All Humans and Animals are stored in a shared "entity" table, but equipment is stored in a separate table.)</p>
  
  <p>This part of code works. The Save() method defined in DbItem properly resolves the DbTable property.</p>
  
  <p>However, then I also have a DbCollection class, which extends the generic C# Collection class. I wish for the DbCollection to be able to automatically determine the correct database table name with reflection.</p>
  
  <p>Hence, if I want to create a list of all equipment, I create a new DbCollection, and the code composes the appropriate SELECT statement (SELECT ... FROM equipment ...). This works.</p>
  
  <p>However, if I want a list of all entities (animals and humans), I have an issue.  "Entity" is marked as abstract, and I should not be able to instantiate it. However, I also do not know how to get the value of Entity.DbTable property.</p>
  
  <p>A simple "fix" is to remove the "abstract" qualified from the Entity class definition. This however does not sound right to me.</p>
  
  <p>Can you please let me know how can I get the value of Entity.DbTable property?</p>
  
  <pre><code>class Program
  {
      abstract class DbItem
      {
          public int Id { get; set; }
          public abstract string DbTable { get; }
  
          public void Save()
          {
              Console.WriteLine($"INSERT INTO {DbTable} (Id) VALUES ({this.Id})...");
          }
      }
  
      abstract class Entity : DbItem
      {
          public sealed override string DbTable { get =&gt; "entities"; }
      }
  
      class Human : Entity { }
  
      class Equipment : DbItem
      {
          public override string DbTable =&gt; "equipment";
      }
  
      class DbCollection&lt;T&gt; : System.Collections.ObjectModel.Collection&lt;T&gt;
      {
          public virtual string DbTable { get
              {
                  Type t = typeof(T);
                  //System.Reflection.PropertyInfo p = t.GetProperty("DbName");
  
                  if(t.IsAbstract)
                  {
                      // What do we do here to get the value of Entity.DbTable?
                      var prop = t.GetProperty("DbTable");
                      // Herein lies the problem: One cannot instantiate an abstract class to provide to the GetValue() method
                      return prop.GetValue(null).ToString(); // System.Reflection.TargetException: 'Non-static method requires a target.'
  
                  }
                  else
                  {
                      var obj = Activator.CreateInstance(t);
                      //return (obj as DbItem).DbTable; // this also works
                      var prop = t.GetProperty("DbTable");
                      return prop.GetValue(obj).ToString();
                  }
              }
          }
  
          public DbCollection()
          {
              Console.WriteLine($"SELECT Id FROM {DbTable} WHERE ...");
          }
  
      }
  
      static void Main(string[] args)
      {
          var h = new Human();
          h.Save(); // 1. Correctly outputs "entities";
  
          var e = new Equipment();
          e.Save(); // 2. Correctly outputs "equipment";
  
          var ec = new DbCollection&lt;Equipment&gt;(); // 3. Correctly outputs "equipment"
  
  
          var hc = new DbCollection&lt;Human&gt;(); // 4. Correctly outputs "entities"
  
          var entityCollection = new DbCollection&lt;Entity&gt;(); // 5. Error.
  
          Console.ReadLine();
  
      }
  }
  </code></pre>