C#中的静态成员继承

时间:2010-02-01 04:13:15

标签: c# inheritance static

我有许多反映数据库中表的类。我想有一个基类具有一些基本功能(比如,它将有一个“isDirty”标志),以及一个字符串的静态数组,其列名出现在数据库中。以下代码不起作用,但说明了我想要做的事情:

public class BaseRecord {  
  public bool isDirty;  
  public object [] itemArray;  
  public static string [] columnNames;    
}

public class PeopleRec : BaseRecord {  
}

public class OrderRec : BaseRecord {  
}

public static void Main() {
  PeopleRec.columnNames = new string[2];
  PeopleRec.columnNames[0]="FIRST_NAME";
  PeopleRec.columnNames[1]="LAST_NAME";

  OrderRec.columnNames = new string[4];
  OrderRec.columnNames[0] = "ORDER_ID";
  OrderRec.columnNames[1] = "LINE";
  OrderRec.columnNames[2] = "PART_NO";
  OrderRec.columnNames[3] = "QTY";
}

public class DoWork<T> where T : BaseRecord {
  public void DisplayColumnNames() {
    foreach(string s in T.columnNames)
      Console.Write("{0}", s);
    }
  public void DisplayItem(T t) {
    for (int i=0; i<itemValues.Length; i++) {
      Console.Write("{0}: {1}",t.columnNames[i],t.itemValues[i])
    }
  }
}

我希望每个派生类都有自己的数据库列名字符串的静态数组,我希望泛型类能够访问这个静态成员,而不需要实例。

但它不起作用:
(A)columnNames是BaseRec,PeopleRec和OrderRec中的相同数组。我不能让columnNames有所不同。 BaseRec.columnNames.Length将为3,因为OrderRec中的columnNames最后被初始化。
(B)符号T.columnNames不编译。

有关如何解决此问题的任何想法?

4 个答案:

答案 0 :(得分:3)

问题在于您要将某些数据与类型相关联,而不是与类型的实例相关联。我不确定在C#中有一种巧妙的方法,但有一种可能性是在Dictionary<Type, string[]>上使用静态BaseRecord。下面是一个例子,您可以通过在BaseRecord上添加一些通用静态成员来初始化/访问记录名称(并添加一些错误检查......)来实现这一点:

using System;
using System.Collections.Generic;

namespace Records
{
    public class BaseRecord
    {
        public bool isDirty;
        public object[] itemArray;

        public static Dictionary<Type, string[]> columnNames = new Dictionary<Type, string[]>();
    }

    public class PeopleRec : BaseRecord
    {
        static PeopleRec()
        {
            string[] names = new string[2];
            names[0] = "FIRST_NAME";
            names[1] = "LAST_NAME";
            BaseRecord.columnNames[typeof(PeopleRec)] = names;
        }
    }

    public class DoWork<T> where T : BaseRecord
    {
        public void DisplayColumnNames()
        {
            foreach (string s in BaseRecord.columnNames[typeof(T)])
                Console.WriteLine("{0}", s);
        }

        public void DisplayItem(T t)
        {
            for (int i = 0; i < t.itemArray.Length; i++)
            {
                Console.WriteLine("{0}: {1}", BaseRecord.columnNames[typeof(T)][i], t.itemArray[i]);
            }
        }
    }

    class Program
    {
        public static void Main()
        {
            PeopleRec p = new PeopleRec
            {
                itemArray = new object[] { "Joe", "Random" }
            };

            DoWork<PeopleRec> w = new DoWork<PeopleRec>();
            w.DisplayColumnNames();
            w.DisplayItem(p);
        }
    }
}

答案 1 :(得分:1)

为什么不创建单独的“全局名称”类,其成员只是包含您需要访问的文本的静态常量字符串。

public static class OrderRecNames{
    public static const string OrderId =  "ORDER_ID";
    public static const string Line = "LINE";
    public static const string PartNo = "PART_NO";
    public static const string Qty = "QTY";
}

编辑:

更好的是,将每个静态类的全局名称设置为他们描述的类的内部类,因此可以键入OrderRecNames.OrderId而不是OrderRec.Names.OrderId,因此该类的目的非常明显。希望有所帮助!

编辑2 :(非常具体)

public class BaseRecord {  
    public bool isDirty;  
    public object [] itemArray;  
}

public class PeopleRec : BaseRecord {  
    class Columns {
        public static const string FirstName =  "FIRST_NAME";
        public static const string LastName = "LAST_NAME";
    }
}

public class OrderRec : BaseRecord {  
    class Columns {
        public static const string OrderId =  "ORDER_ID";
        public static const string Line = "LINE";
        public static const string PartNo = "PART_NO";
        public static const string Qty = "QTY";
    }
}

答案 2 :(得分:1)

数组是引用类型。只需在基类中包含一个非静态属性,并通过为所有要引用的实例创建静态成员,在派生类中实现它。开销非常小。我保证你不会注意到。

哦,ReadOnlyCollection<string>比这些名字的数组要好。像这样:

public class BaseRecord {  
  public bool isDirty;  
  public IEnumerable<Object> items;  
  public ReadOnlyCollection<string> columnNames;    
}

public class BaseRecord {  
  public bool isDirty;  
  public IList<Object> items;  

  public Object this[int index]
  {
     get { return items[index];}
     set { items[index] = value;}
  }

  public ReadOnlyCollection<string> columnNames;    
}

或使用C#4(assuming my understanding of dynamic is correct):

public class BaseRecord {  
  public bool isDirty;  
  public IList<dynamic> items;  

  public dynamic this[int index]
  {
     get { return items[index];}
     set { items[index] = value;}
  }

  public ReadOnlyCollection<string> columnNames;    
}

但是,我真的怀疑这堂课的好处。它提供的界面只提供对实际数据的非类型访问,这不是很有用。您可能会尝试使用泛型来修复它,但最终会得到类似这样的内容:

public Record<T>
{
    public bool isDirty;
    public ReadOnlyCollection<string> columnNames;
    public T data;
}

其中每个“T”是一个完全不同的类,其中包含来自单个表的字段。它没有为您提供良好的语法,当您实现其他类时,您也可以直接添加列名和isDirty成员。

在我看来,当我之前提到“界面”时,更好的解决方案。你真正想要的东西看起来更像是这样:

public IRecord
{
    bool isDirty;
    ReadOnlyCollection<string> columnNames;
}

可能

public IRecord
{
    bool isDirty;
    ReadOnlyCollection<string> columnNames;

    dynamic this[int index]
    {
        get;
        set;
    }
}

答案 3 :(得分:-1)

如果必须有静态变量,我会这样做:

  public class BaseRecord
  {
     public bool isDirty;
     public object[] itemArray;
     public static string[] columnNames;

     public void DisplayColumnNames()
     {
        foreach (string s in columnNames)
           Console.Write("{0}\n", s);
     }

     public void DisplayItem()
     {
        for (int i = 0; i < itemArray.Length; i++)
        {
           Console.Write("{0}: {1}\n", columnNames[i], itemArray[i]);
        }
     }
  }

  public class PeopleRec : BaseRecord
  {
     public PeopleRec()
     {
     }
  }

  public class OrderRec : BaseRecord
  {
     public OrderRec()
     {
     }
  }

  public static void Main()
  {
     PeopleRec.columnNames = new string[2];
     PeopleRec.columnNames[0] = "FIRST_NAME";
     PeopleRec.columnNames[1] = "LAST_NAME";

     OrderRec.columnNames = new string[4];
     OrderRec.columnNames[0] = "ORDER_ID";
     OrderRec.columnNames[1] = "LINE";
     OrderRec.columnNames[2] = "PART_NO";
     OrderRec.columnNames[3] = "QTY";

     BaseRecord p = new PeopleRec();
     p.DisplayColumnNames();
     p.itemArray = new object[2];
     p.itemArray[0] = "James";
     p.itemArray[1] = "Smith";
     p.DisplayItem();

     BaseRecord o = new OrderRec();
     o.DisplayColumnNames();
     o.itemArray = new object[4];
     o.itemArray[0] = 1234;
     o.itemArray[1] = 1;
     o.itemArray[2] = 39874;
     o.itemArray[3] = 70;
     o.DisplayItem();
  }

否则,我会将它们更改为公共属性(无静态),只需将它们添加到创建的派生类数组中(使用属性调用删除静态调用)。