私は非常に単純なフレームワークで、CRUD機能を自動化したいと思っています。この質問の目的のために、以下のコードを作成しました。問題を説明するために単純化しました。抽象クラスで定義されたプロパティ値を取得
すべての項目は、(CRUD関数を含む)基本クラス「DbItem」から派生します。これにより、子クラスは追加機能を提供し、DbItemが格納されるテーブル名も定義します。たとえば、 "Equipment"と "Entity"は両方ともDbItemから派生し、テーブル名(それぞれ "equipment"と "entities")を定義します。しかし、 "Entity"クラスは抽象クラスであり、 "Human"クラスと "Animal"クラスによってさらに導出されます。 (すべての人間と動物は共有された "エンティティ"テーブルに保存されますが、機器は別のテーブルに保存されます)。
この部分は動作します。 DbItemで定義されたSave()メソッドは、DbTableプロパティを適切に解決します。
しかし、DbCollectionクラスもあり、これは汎用C#コレクションクラスを拡張しています。私は、DbCollectionが反映された正しいデータベーステーブル名を自動的に決定できることを望みます。
したがって、すべての機器のリストを作成したい場合は、新しいDbCollectionを作成し、コードが適切なSELECT文(SELECT ... FROM equipment ...)を作成します。これは機能します。
しかし、すべてのエンティティ(動物や人間)のリストが必要な場合は、問題があります。 「エンティティ」は抽象としてマークされており、インスタンス化することはできません。しかし、Entity.DbTableプロパティの値を取得する方法もわかりません。
簡単な「修正」は、Entityクラス定義から修飾された「抽象」を削除することです。しかし、これは私にとって正しいことではありません。
Entity.DbTableプロパティの値を取得する方法を教えてください。
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 => "entities"; }
}
class Human : Entity { }
class Equipment : DbItem
{
public override string DbTable => "equipment";
}
class DbCollection<T> : System.Collections.ObjectModel.Collection<T>
{
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<Equipment>(); // 3. Correctly outputs "equipment"
var hc = new DbCollection<Human>(); // 4. Correctly outputs "entities"
var entityCollection = new DbCollection<Entity>(); // 5. Error.
Console.ReadLine();
}
}
あなたは何を意味しますか:アブストラクトを削除すると、あなたの右には聞こえません。なぜそれは抽象クラスでなければならないのですか?あなたは同じものの必要性を説明してもらえますか? – bhuvin
人間でも動物でもないエンティティは決して存在しないので、「エンティティ」は抽象的でなければならないと私は思うだろう。 私は、人間や動物に固有のもの(および対応するクラスでのみ定義されているもの)に加えて、人間と動物が共有するいくつかのプロパティ/メソッド(例:名前、住所...)を含むために "エンティティ"を使用します。 私はエンティティを抽象としてマークすることは、概念的に正しいと理解しました。 これが当てはまらない場合は、「抽象的な」を削除することをお勧めします:)。 – Ziggga
あなたは静的メンバーを探しています。 '[Attribute]'も妥当です。 –