#c# #reflection #anonymous-types
#c# #отражение #анонимные типы
Вопрос:
Допустим, у нас есть следующие классы, определенные следующим образом
class Test {
public string Name { get; set; }
public string Type { get; set; }
public string SomeOtherValue { get; set; }
public Address Address { get; set; }
}
class Address {
public string AddressText { get; set; }
public string PostalCode { get; set; }
}
Затем мне нужно внутри метода что-то сделать с одним или несколькими свойствами в этом классе, и я хотел бы определить, какие именно, безопасным для компиляции способом. Итак, я хочу вызвать метод следующим образом:
MyFunction<Test>(t => new {t.Name, t.Address.AddressText});
Затем внутри моей функции мне нужно знать это «Имя» и «Адрес».AddressText» — это выбранные свойства, но я не уверен, как их получить
public void MyFunction<T>(Func<T, ?> param){
...
}
Итак, моя проблема в том, что я не могу установить? как TResult
Func
в любом хорошем смысле. Если бы я мог правильно это настроить, я думаю, я мог бы взять typeOf(TResult).GetProperties()
, но я чувствую, что мне не хватает части, чтобы заставить это работать.
Обновить
Я вижу, что есть путаница в том, что я пытаюсь здесь сделать. Я приведу пример из драйвера MongoDB, который ведет себя так же, как я хотел бы, чтобы мой код делал
Итак, допустим, testcoll
это коллекция Test
объектов. В этом случае это сработает и вернет мне только список анонимного типа, который имеет только свойство Name .
await testcoll.Find(t => t.Type == "sometype").Project(t => new {t.Name}).ToListAsync();
Итак, вопрос в основном. Внутри Project
, как я могу определить, что Name
это те свойства, которые я хочу извлечь из базы данных, и вернуть в результате анонимный тип?
Комментарии:
1. Извините, просто опечатка. Так привыкли писать prop для автозаполнения свойств в IDE 😉
2. Почему вы не можете создать класс / структуру или даже кортеж? Может ли вызывающий объект выбирать другие свойства?
3. Да, это связано с проекцией для поиска. Это должно указывать, какие поля я заинтересован в возврате, и будет отличаться каждый раз, когда я вызываю myFunction
4.Тогда вы
MyFunction
не можете точно знать, что свойстваName
иAddressText
существуют, верно? Возможно, вы не «заинтересованы в этих областях».MyFunction
невозможно сделать это с безопасностью типов во время компиляции, поскольку не существует вариационных обобщений, если только вас не интересует постоянное количество полей каждый раз.5. Говоря о безопасности типов компиляции, я имел в виду вызов функции. Я хочу, чтобы параметр был новым {t.Name , т.е.Адрес. AddressText}, а не массив магических строк, подобных этому new []{ «Имя», «Адрес. AddressText»}. Но я понимаю, что получение отправленных фактических значений должно быть выполнено во время выполнения, и это совершенно нормально.
Ответ №1:
Хорошо, теперь я решил эту проблему. Возможно, проблема в том, что мое объяснение в вопросах и есть проблема. Я хочу получить безопасность во время компиляции для параметра, а не получать фактическое значение времени компиляции. Это, конечно, не сработало бы.
Поэтому я хочу иметь возможность писать
MyFunction<Test>(t => new {t.Name, t.Address.AddressText});
Вместо
MyFunction<Test>(new {"Name", "Address.AddressText"});
Так что я не получу никаких опечаток в отправленных параметрах и удостоверюсь, что любое изменение тестового объекта приведет к ошибке во время компиляции.
Я решил это так:
public void MyFunction<T>(Expression<Func<T, object>> lambda)
{
List<string> arguments;
if (lambda.Body is NewExpression)
{
var args = (lambda.Body as NewExpression).Arguments;
arguments = args.Select(a =>
{
var aText = a.ToString();
var dotIndex = aText.IndexOf(".");
var result = aText.Substring(dotIndex 1);
return resu<
}).ToList();
}
else
{
throw new ArgumentException();
}
}
<do whatever I need to do here with the arguments list>
}
Итак, для примера выше, где аргумент t => new {t.Name, t.Address.AddressText}
— это, который будет преобразован в список со строками "Name"
и "Address.AddressText"
внутри метода.