C # Generics список списков

#c# #list #generics

#c# #Список #общие

Вопрос:

Привет, у меня простая проблема с приложением sql, которую я, похоже, не способен решить. Это предполагает использование дженериков, с которыми я не слишком знаком. Я проводил исследования здесь и в Интернете, но, похоже, я не нашел подходящего решения для своего случая.

У меня есть два класса: таблица и поле. Я хочу, чтобы таблица содержала список полей, и я хочу, чтобы каждое поле содержало список набора записей. Сложная часть заключается в том, что я хочу, чтобы пользователь выбирал, какой тип набора записей реализовать.

Определение класса Table является:

 namespace DBlib
{
    public class DBTable<T>
    {
        public List<DBField<T>> FieldName = new List<DBField<T>>();

        public DBTable (string NameOfTable)
        {
        }

        public void AddField (string Name)
        {
            DBField<T> TempList = new DBField<T>();
            FieldName.Add(TempList);
        }
    }
}
  

Определение класса поля является:

 namespace DBlib
{
    public class DBField<T>
    {
        public List<T> RecordSet = new List<T>();

        public DBField()
        {            
        }         
    }
}
  

С помощью этого кода пользователь вынужден приводить тип при создании экземпляра DBTable. Это неверно. Я хочу, чтобы пользователь приводил тип при вызове метода AddField. Можете ли вы предложить простой способ решения этой проблемы?

ОБНОВЛЕНИЕ # 1 Я изменил tempList как DBField в определении класса таблицы. Извините за возникшую путаницу.

Я хочу также добавить этот код, чтобы лучше объяснить, в чем моя проблема. Предполагая, что первое поле таблицы является целым числом, пользователь должен выполнить:

 namespace SpecifytheName
{
    public class User
    {
        DBTable<int> Table = new DBTable<int>(); 

        public User()
        {            
        }         
    }
}
  

Вместо этого я хочу, чтобы пользователь делал:

 namespace SpecifytheName
{
    public class User
    {
        DBTable Table1 = new DBTable("Table1"); 

        // SPECIFY THE TYPE OF FIELD1 ONLY AT THIS POINT
        Table1.AddField<int>("Field1");  //or something like this

        public User()
        {            
        }         
    }
}
  

Комментарии:

1. TempList должно быть типа List<DBField<T>> , чтобы вышеприведенное работало в любом случае, не так ли

2. Но как именно пользователь должен указывать (во время выполнения?) что тип должен быть «int» (или «double» или что-то еще?)

3. Что я считаю наиболее важным на данный момент, не зная больше подробностей о том, что вы на самом деле пытаетесь сделать, так это почему вы не используете стандартные типы данных, связанные с работой с SQL?

4. Похоже, он пытается изобрести велосипед

5. Что вам нужно понять о C # generics, так это то, что часть программы, закодированная для общих типов (класс или метод), не должна знать тип во время компиляции (я здесь чрезмерно упрощаю). НО где-то во время компиляции часть программы, которая ИСПОЛЬЗУЕТ эти классы или методы, должна указывать тип. Это не то, что можно извлечь из воздуха во время выполнения.

Ответ №1:

Я бы вообще решил эту проблему, используя не универсальный интерфейс для хранения ваших полей.

Итак, начните с этого интерфейса:

 public interface IDBField
{
    IList RecordSet { get; }
    Type FieldType { get; }
}
  

Теперь реализуйте DBField<T> так:

 public class DBField<T> : IDBField
{
    public List<T> RecordSet = new List<T>();

    IList IDBField.RecordSet
    {
        get
        {
            return this.RecordSet;
        }
    }

    Type IDBField.FieldType
    {
        get
        {
            return typeof(T);
        }
    }      
}
  

Затем вы можете реализовать DBTable следующим образом:

 public class DBTable
{
    public List<IDBField> FieldName = new List<IDBField>();

    public void AddField<F>(string Name)
    {
        FieldName.Add(new DBField<F>());
    }
}
  

Вы можете использовать FieldType свойство on IDBField для определения типа поля, а затем использовать отражение по мере необходимости, чтобы использовать значения RecordSet соответствующим образом.

Комментарии:

1. Разве чего-то не хватает в том, как используется имя поля?

2. @Enigmativity Привет, спасибо. это именно то, что я искал, и я голосую за это как за ответ, который решает проблему. Еще раз спасибо!

3. @RenniePet — Да, есть, но этого тоже не хватало в вопросе, поэтому я его не учел.

Ответ №2:

Единственный способ, которым я могу видеть, что это работает, — это не использовать Generics, а просто использовать Object класс.

например:

 public class DBTable
{
    public List<DBField<Object>> FieldName = new List<DBField<Object>>();

    public DBTable (string NameOfTable)
    {
    }

    public void AddField(string Name)
    {
        List<DBField<Object>> TempList = new List<DBField<Object>>();
        FieldName.Add(TempList);
    }
}
  

Это будет означать, что вы можете использовать любой тип в RecordSet объекте, не ограничивая тип в классе DBTable.

Я мог бы немного ошибиться здесь, поскольку я не уверен, чего вы пытаетесь достичь, например, вы ничего не делаете с Name параметром, переданным в AddField метод, и ваш TempList объект не того же типа, что и, FieldName поэтому он должен вызывать некоторые ошибки..

Редактировать:

Я думаю, что я более четко понимаю, что вы пытаетесь сделать, попробуйте это —

 public class DBTable
{
    public List<DBField<Object>> FieldName = new List<DBField<Object>>();

    public DBTable (string NameOfTable)
    {
    }

    public void AddField<FieldType>(string Name)
    {
        DBField<FieldType> field = new DBField<FieldType>(Name);
        FieldName.Add(field);
    }
}
  

Таким образом, каждое поле (столбец) по-прежнему принудительно привязывается к типу, но DBTable не привязан к тому же типу.

Комментарии:

1. В этом случае, вероятно, было бы проще использовать неровный массив, а не по-прежнему создавать DBField как универсальный с типом Object

2. Я понимаю, чего вы пытаетесь достичь своим ответом, но я не верю, что OP имеет четкое представление о дженериках и о том, как они работают и функционируют в C #.

3. Он упомянул об этом в своем посте. Я думаю, что более конкретно нам нужно знать, чего он пытается достичь, независимо от использования его дженериков.

4. @LeonNewswanger Да, у меня пока нет четкого представления о том, как работают дженерики. Я читаю и кодирую (и делаю ошибки), пытаясь их изучить. В общем, я пытаюсь создать простую пользовательскую библиотеку, которая работает с базой данных. Я хочу, чтобы библиотека предоставляла пользователю объект с именем Table и объект с именем Field. В поле объекта у меня будет набор записей, который можно очистить и использовать для сохранения данных после оператора SELECT или для сбора данных для ВСТАВКИ или ОБНОВЛЕНИЯ. Что-то простое, чтобы мои ноги промокли. Спасибо за вашу помощь!

5. @LuckyLuke Тогда вы действительно пытаетесь изобрести велосипед. Отличные библиотеки для работы с SQL уже существуют. Если вы хотите узнать, как правильно использовать generics, вам следует начать с чего-то немного более простого.