Этот метод сохраняет одну строку 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.