Статическое членское наследование в C#

У меня есть много классов, которые отражают таблицы в базе данных. Я хотел бы иметь базовый класс, который имеет некоторую основную функциональность (скажите, она имела бы флаг "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. Длина была бы 3, потому что columnNames в OrderRec инициализируется в последний раз.
(B) Нотация T.columnNames не компилирует.

Какие-либо идеи о том, как зафиксировать это?

6
задан Marc Meketon 1 February 2010 в 04:13
поделиться

4 ответа

Проблема в том, что вы хотите связать некоторые данные с типами, а не с экземплярами типов. Я не уверен, что в C # есть изящный способ сделать это, но одна возможность - использовать статический Dictionary в 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);
        }
    }
}
3
ответ дан 17 December 2019 в 07:04
поделиться

Почему бы Вам просто не создать отдельные классы "Global Names", членами которых являются просто статические константные строки, содержащие текст, к которому Вам необходимо получить доступ.

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";
}

Правка:

Лучше сделать каждый статический класс "Global Names" внутренними классами описанных ими классов, поэтому вместо 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";
    }
}
1
ответ дан 17 December 2019 в 07:04
поделиться

Если вам нужно было сделать статическую переменную, я бы сделал это:

  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();
  }

в противном случае я бы изменил их в публичные свойства (не статично) и просто добавляю их в созданный производный классный массив ( Удалите статический вызов с вызовом свойств).

-1
ответ дан 17 December 2019 в 07:04
поделиться

Массивы являются ссылочными типами. Просто включите нестатическое свойство в базу и реализуйте его в производных классах, создав статический член для всех экземпляров, на которые будут ссылаться. Накладные расходы действительно небольшие. Обещаю, ты не заметишь.

Да, и ReadOnlyCollection было бы лучше, чем массив для этих имен. Примерно так:

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 ( при условии, что я правильно понимаю динамику ):

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;
    }
}
1
ответ дан 17 December 2019 в 07:04
поделиться
Другие вопросы по тегам:

Похожие вопросы: