Этот метод сохраняет одну строку SQL-запроса в переменной анонимного типа. Вы должны передать прототип в метод. Если какое-либо свойство анонимного типа не может быть найдено в запросе sql, оно заполняется значением prototype-value. C # создает конструкторы для своих анонимных классов, параметры имеют те же имена, что и свойства (только для чтения).

дал функцию, которая принимает команду SQL и выдает выходные данные, которые затем можно использовать для заполнения списка экземпляров классов. Код прекрасно работает. Я включил немного упрощенную версию без обработки исключений здесь просто для справки - пропустите этот код, если вы хотите решить проблему. Если у вас есть предложения здесь, я все уши.

    public List<T> ReturnList<T>() where T : new()
    {
        List<T> fdList = new List<T>();
        myCommand.CommandText = QueryString;
        SqlDataReader nwReader = myCommand.ExecuteReader();
        Type objectType = typeof (T);
        FieldInfo[] typeFields = objectType.GetFields();
        while (nwReader.Read())
        {
            T obj = new T();
            foreach (FieldInfo info in typeFields)
            {
                for (int i = 0; i < nwReader.FieldCount; i++)
                {
                    if (info.Name == nwReader.GetName(i))
                    {
                        info.SetValue(obj, nwReader[i]);
                        break;
                    }
                }
            }
            fdList.Add(obj);
        }
        nwReader.Close();
        return fdList;
    }

Как я уже сказал, это работает просто отлично. Тем не менее, я хотел бы иметь возможность вызывать аналогичную функцию санонимный класс по понятным причинам.

Вопрос № 1: кажется, что я должен создать анонимный классэкземпляр в моем звонке на мою анонимную версию этой функции - это правильно? Пример вызова:

.ReturnList(new { ClientID = 1, FirstName = "", LastName = "", Birthdate = DateTime.Today });

Вопрос № 2: анонимная версия моей функции ReturnList приведена ниже. Может кто-нибудь сказать мне, почему вызов info.SetValue просто ничего не делает? Он не возвращает ошибку или что-либо еще, но не изменяет значение целевого поля.

    public List<T> ReturnList<T>(T sample) 
    {
        List<T> fdList = new List<T>();
        myCommand.CommandText = QueryString;
        SqlDataReader nwReader = myCommand.ExecuteReader();
        // Cannot use FieldInfo[] on the type - it finds no fields.
        var properties = TypeDescriptor.GetProperties(sample); 
        while (nwReader.Read())
        {
            // No way to create a constructor so this call creates the object without calling a ctor. Could this be a source of the problem?
            T obj = (T)FormatterServices.GetUninitializedObject(typeof(T)); 
            foreach (PropertyDescriptor info in properties)  
            {
                for (int i = 0; i < nwReader.FieldCount; i++)
                {
                    if (info.Name == nwReader.GetName(i))
                    {
                        // This loop runs fine but there is no change to obj!!
                        info.SetValue(obj, nwReader[i]);
                        break;
                    }
                }
            }
            fdList.Add(obj);
        }
        nwReader.Close();
        return fdList;
    }

Есть идеи?

Примечание: Когда я попытался использовать массив FieldInfo, как я делал в приведенной выше функции, массив typeFields содержал ноль элементов (хотя objectType показывает имена полей - странно). Таким образом, вместо этого я использую TypeDescriptor.GetProperties.

Любые другие советы и рекомендации по использованию рефлексии или анонимных классов здесь уместны - я относительно новичок в этом конкретном уголке языка C #.

ОБНОВЛЕНИЕ: Я должен поблагодарить Джейсона за ключ к решению этой проблемы. Ниже приведен пересмотренный код, который создаст список экземпляров анонимных классов, заполнив поля каждого экземпляра из запроса.

   public List<T> ReturnList<T>(T sample)
   {
       List<T> fdList = new List<T>();
       myCommand.CommandText = QueryString;
       SqlDataReader nwReader = myCommand.ExecuteReader();
       var properties = TypeDescriptor.GetProperties(sample);
       while (nwReader.Read())
       {
           int objIdx = 0;
           object[] objArray = new object[properties.Count];
           foreach (PropertyDescriptor info in properties) 
               objArray[objIdx++] = nwReader[info.Name];
           fdList.Add((T)Activator.CreateInstance(sample.GetType(), objArray));
       }
       nwReader.Close();
       return fdList;
   }

Обратите внимание, что запрос был создан и параметры инициализированы в предыдущих вызовах методов этого объекта. Исходный код имел комбинацию внутреннего / внешнего цикла, чтобы пользователь мог иметь поля в своем анонимном классе, которые не совпадали с полем. Однако, чтобы упростить дизайн, я решил не допустить этого и вместо этого принял доступ к полю db, рекомендованный Джейсоном. Кроме того, спасибо Дэйву Марклу за то, что он помог мне понять больше о компромиссах в использовании Activator.CreateObject () по сравнению с GenUninitializedObject.

Ответы на вопрос(1)

Ваш ответ на вопрос