获取 属性 摘要中定义的值 class
Get property value defined in an abstract class
我正在开发一个非常简单的框架,我想在其中自动执行 CRUD 功能。出于这个问题的目的,我创建了下面的代码,经过简化只是为了说明我的问题。
所有项目都派生自(抽象)基础 class "DbItem"(其中包含 CRUD 函数),子 classes 提供额外的功能,并且还定义了 table 存储 DbItems 的名称。例如,"Equipment" 和 "Entity" 都派生自 DbItem,并定义 table 名称(分别为 "equipment" 和 "entities")。然而,"Entity" class 是抽象的,由 "Human" 和 "Animal" class 进一步推导出来。 (所有人类和动物都存储在共享 "entity" table 中,但设备存储在单独的 table 中。)
这部分代码有效。 DbItem 中定义的 Save() 方法正确解析了 DbTable 属性.
但是,我还有一个 DbCollection class,它扩展了通用 C# 集合 class。我希望 DbCollection 能够通过反射自动确定正确的数据库 table 名称。
因此,如果我想创建一个包含所有设备的列表,我会创建一个新的 DbCollection,代码组成适当的 SELECT 语句(SELECT ... FROM equipment ... ).这行得通。
但是,如果我想要所有实体(动物和人类)的列表,我有一个问题。 "Entity" 被标记为抽象的,我应该无法实例化它。但是,我也不知道如何获取 Entity.DbTable 属性.
的值
一个简单的"fix"是从实体class定义中删除限定的"abstract"。然而,这对我来说听起来不对。
你能告诉我如何获得 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();
}
}
您希望在您的第五个案例中发生什么?
绝对没有办法创建 abstract
class 的实例。从实体 class 中删除 abstract
关键字。如果你想阻止 Entity
class 的外部创建,你可以使用 internal
构造函数。
由于这是一个集合,您还可以使用集合的第一个条目来获得 DbTable
结果 - 这可能很危险,因为第二个条目可能是另一种类型。
不要使用 属性,使用属性。那就是你想要的,对吧?要将 class 与编译时固定的 table 名称相关联?
首先,创建一个存储 table 名称的自定义属性 class:
[AttributeUsage(AttributeTargets.Class | Inherited = true)]
public class DbTableAttribute: System.Attribute
{
private readonly string _name;
public string Name { get { return _name; } }
public DbTableAttribute(string name)
{
_name = name;
}
}
将其添加到您的 human/animal/entity/DbItem classes:
[DbTable("entities")]
abstract class Entity : DbItem
{
//Don't need this any more
//public sealed override string DbTable { get => "entities"; }
}
然后像这样检索它:
public string GetDbTable<T>() where T : DbItem
{
var attr = typeof(T).GetCustomAttributes(
typeof(DbTableAttribute), true
).FirstOrDefault() as DbTableAttribute;
return attr?.Name;
}
我正在开发一个非常简单的框架,我想在其中自动执行 CRUD 功能。出于这个问题的目的,我创建了下面的代码,经过简化只是为了说明我的问题。
所有项目都派生自(抽象)基础 class "DbItem"(其中包含 CRUD 函数),子 classes 提供额外的功能,并且还定义了 table 存储 DbItems 的名称。例如,"Equipment" 和 "Entity" 都派生自 DbItem,并定义 table 名称(分别为 "equipment" 和 "entities")。然而,"Entity" class 是抽象的,由 "Human" 和 "Animal" class 进一步推导出来。 (所有人类和动物都存储在共享 "entity" table 中,但设备存储在单独的 table 中。)
这部分代码有效。 DbItem 中定义的 Save() 方法正确解析了 DbTable 属性.
但是,我还有一个 DbCollection class,它扩展了通用 C# 集合 class。我希望 DbCollection 能够通过反射自动确定正确的数据库 table 名称。
因此,如果我想创建一个包含所有设备的列表,我会创建一个新的 DbCollection,代码组成适当的 SELECT 语句(SELECT ... FROM equipment ... ).这行得通。
但是,如果我想要所有实体(动物和人类)的列表,我有一个问题。 "Entity" 被标记为抽象的,我应该无法实例化它。但是,我也不知道如何获取 Entity.DbTable 属性.
的值一个简单的"fix"是从实体class定义中删除限定的"abstract"。然而,这对我来说听起来不对。
你能告诉我如何获得 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();
}
}
您希望在您的第五个案例中发生什么?
绝对没有办法创建 abstract
class 的实例。从实体 class 中删除 abstract
关键字。如果你想阻止 Entity
class 的外部创建,你可以使用 internal
构造函数。
由于这是一个集合,您还可以使用集合的第一个条目来获得 DbTable
结果 - 这可能很危险,因为第二个条目可能是另一种类型。
不要使用 属性,使用属性。那就是你想要的,对吧?要将 class 与编译时固定的 table 名称相关联?
首先,创建一个存储 table 名称的自定义属性 class:
[AttributeUsage(AttributeTargets.Class | Inherited = true)]
public class DbTableAttribute: System.Attribute
{
private readonly string _name;
public string Name { get { return _name; } }
public DbTableAttribute(string name)
{
_name = name;
}
}
将其添加到您的 human/animal/entity/DbItem classes:
[DbTable("entities")]
abstract class Entity : DbItem
{
//Don't need this any more
//public sealed override string DbTable { get => "entities"; }
}
然后像这样检索它:
public string GetDbTable<T>() where T : DbItem
{
var attr = typeof(T).GetCustomAttributes(
typeof(DbTableAttribute), true
).FirstOrDefault() as DbTableAttribute;
return attr?.Name;
}