C#

时间:2015-05-08 15:18:23

标签: c# generics inheritance

出于我的目的,我有一个基于数据库的对象的基类(不完全是这样,但为了清楚起见,我们保持这种方式)。
所有派生类都需要一个TableName成员,其中包含数据库表的名称
我需要的是一种满足以下所有要点的方法:

  1. 以下函数适用于所有派生类:

    
    List<T> ReadAll<T>() where T: BaseClass, new()
    {
        List resultList = new List();
        var results = doQuery("SELECT * FROM " + T.TableName);
        foreach (var r in results)
        {
            resultList.Add(new T(r));
        }
        return resultList;
    }
     

    (从表中读取所有记录 - 需要表名)

  2. 每当我创建一个新的派生类时,基类的继承需要强制我添加/覆盖TableName成员,否则代码不应该编译(无论如何都是它的目的之一);

    < / LI>
  3. TableName成员应该是静态的(或者那个目的),因为我不需要派生类型的“假”实例只是为了点而访问常量成员1。

现在,假设我的目的是明智的而不是基于错误的假设,我怎样才能达到所有这些目的,考虑到(出于好的理由)C#不允许继承静态成员?
如果您认为我错误地认为所有要点应该可以一起实现,您认为我应该如何改变我的设计?

3 个答案:

答案 0 :(得分:1)

你不能覆盖静态成员,因此为了每个类的不同而拥有一个静态字段通常是行不通的。如果您需要每个类的此类数据,那么您谈的是元数据,可以使用属性创建

[AttributeUsage(AttributeTargets.Class)]
public class TableNameAttribute : Attribute
{
    private readonly string _name;
    public string Name {get { return _name; } }

    public TableNameAttribute(string name) { _name = name; }
}

然后在每个班级

[TableName("Derived")]
public class DerviedClass { /*...*/ }

但是,这在编译时无法解决,因此当给定类中不存在[TableName]时,您需要确保添加正确的处理。如果你需要被迫总是确保属性存在,那就写一些好的单元测试,也许noe会扫描你的程序集并检查所有被正确标记的类型,或者遵循“所有代码必须在执行之前运行一次”规则。请注意,通过良好实践和测试在运行时强制执行此操作,您还可以更轻松地避免错误表格名称的不可避免的麻烦。

使用属性,除非您编写静态属性来访问表名属性,否则不会需要将泛型约束为单数类型。

答案 1 :(得分:0)

您不需要静态成员来强制每个类要求&#34; TableName&#34;成员 - 只需将其作为一个抽象属性:

public abstract class BaseClass
{
    public abstract string TableName {get;}
}

public class DerivedClass : BaseClass
{
   public override string TableName {get {return "Derived";} }
}

使abstract强制继承类来实现属性 - 无论是使用静态属性,常量,只读属性还是其他东西都可以使用它们。

答案 2 :(得分:0)

这里有两个问题:

  1. 您需要静态成员继承,C#不支持。
  2. 您正在尝试将表名硬编码为一组类,因此最终会导致责任的扩散。如果需要更改表名,则可能必须转到代码中的多个位置来解决问题。
  3. 两者的解决方案是拥有一个位置,例如包含将类名映射到表名的字典。然后,每个派生类都可以在其构造函数中从BaseClass调用以下受保护方法,以获取它们自己的表名:

    protected string TableName()
    {
        return ClassTableMappings.GetTableName(this.GetType().Name);
    }