Работа с анонимными типами С#
Я вызываю метод, который возвращает переменную List, содержащую объекты анонимного типа С#. Например:
List<object> list = new List<object>();
foreach ( Contact c in allContacts ) {
list.Add( new {
ContactID = c.ContactID,
FullName = c.FullName
});
}
return list;
Как ссылаться на свойства этого типа в коде, над которым я работаю, например,
foreach ( object o in list ) {
Console.WriteLine( o.ContactID );
}
Я знаю, что мой пример невозможен, я только написал, что хочу сказать, что мне нужно точно идентифицировать каждое свойство анонимного типа.
Спасибо!
Решение
Не один из ответов правильный и/или предлагает рабочее решение. Я закончил использовать вариант 3 ответа Грега. И я узнал что-то очень интересное в отношении dynamic
в .NET 4.0!
Ответы
Ответ 1
Вы не можете вернуть список анонимного типа, это должен быть список object
. Таким образом, вы потеряете информацию о типе.
Вариант 1
Не используйте анонимный тип. Если вы пытаетесь использовать анонимный тип более чем одним методом, создайте настоящий класс.
Вариант 2
Не уменьшайте анонимный тип до object
. (должен быть одним способом)
var list = allContacts
.Select(c => new { c.ContactID, c.FullName })
.ToList();
foreach (var o in list) {
Console.WriteLine(o.ContactID);
}
Вариант 3
Используйте ключевое слово dynamic. (Требуется .NET 4)
foreach (dynamic o in list) {
Console.WriteLine(o.ContactID);
}
Вариант 4
Используйте грязное отражение.
Ответ 2
foreach ( var o in list ) {
Console.WriteLine( o.ContactID );
}
это будет работать, только если список IEnumerable<anonymous type>
, например:
var list = allContacts.Select(c => new {
ContactID = c.ContactID,
FullName = c.FullName
});
}
но вы не можете возвращать анонимные типы, потому что вы должны определить тип возвращаемого значения (вы не можете вернуть var
), а анонимные типы не могут иметь имена. вам нужно создать не-анонимный тип, если вы его передадите. На самом деле анонимные типы не должны использоваться слишком много, за исключением внутренних запросов.
Ответ 3
Если у вас есть такой способ:
List<object> GetContactInfo() {
List<object> list = new List<object>();
foreach ( Contact c in allContacts ) {
list.Add( new {
ContactID = c.ContactID,
FullName = c.FullName
});
}
return list;
}
Вы не должны этого делать, но есть очень уродливый, а не будущий метод, который вы можете использовать:
static T CastByExample<T>(object target, T example) {
return (T)target;
}
// .....
var example = new { ContactID = 0, FullName = "" };
foreach (var o in GetContactInfo()) {
var c = CastByExample(o, example);
Console.WriteLine(c.ContactID);
}
Он полагается на факт (который может измениться!), что компилятор повторно использует анонимные типы для типов с одинаковой "формой" (именами и типами свойств). Поскольку ваш "пример" соответствует "форме" типа в методе, тот же тип повторно используется.
Динамические переменные в С# 4 - лучший способ решить эту проблему.
Ответ 4
Вы не можете сделать это с анонимными типами. Просто создайте класс/структуру Contact и используйте это.
List<object> list = new List<object>();
foreach ( Contact c in allContacts ) {
list.Add( c );
}
Затем вы можете сделать это:
foreach ( var o in list ) {
Console.WriteLine( o.ContactID );
}
... или это:
foreach ( object o in list ) {
Console.WriteLine( ((Contact)o).ContactID ); //Gives intellisense
}
Конечно, вы должны в этом случае просто создать список контактов вместо списка объектов:
List<Contact> list = new List<Contact>();
foreach ( Contact c in allContacts ) {
list.Add( c );
}
РЕДАКТИРОВАТЬ: Пропущенная существенная часть вопроса. Теперь исправлено.
EDIT: Изменен ответ еще раз. См. Выше.
Ответ 5
замена объекта на var для каждой конструкции может работать
Ответ 6
Я знаю, что опаздываю на вечеринку, но я изучаю что-то еще и нашел эту статью которая отвечает на ваш вопрос.
Можно вернуть список объектов обратно в анонимный тип.
public static void Main()
{
foreach (object item in GetList())
{
var x = Cast(item, new { ContactID = 0, FullName = "" });
Console.WriteLine(x.ContactID + " " + x.FullName);
}
}
public static IEnumerable<object> GetList()
{
yield return new { ContactID = 4, FullName = "Jack Smith" };
yield return new { ContactID = 5, FullName = "John Doe" };
}
public static T Cast<T>(object obj, T type)
{
return (T)obj;
}
Ответ 7
список назад
public static void Main()
{
foreach (object item in GetList())
{
var x = Cast(item, new { ContactID = 0, FullName = "" });
Console.WriteLine(x.ContactID + " " + x.FullName);
}
}
public static IEnumerable<object> GetList()
{
yield return new { ContactID = 4, FullName = "Jack Smith" };
yield return new { ContactID = 5, FullName = "John Doe" };
}
public static T Cast<T>(object obj, T type)
{
return (T)obj;
}
Ответ 8
я использовал бы
allContacts
.Select(c => new { c.ContactID, c.FullName })
.ToList()
.ForEach(c => {
...do stuff;
});
тогда вам не нужно вообще объявлять.
я полагаю, что меньше декларации, менее полуточек приводит к меньшей ошибке