Работа с анонимными типами C # - PullRequest
25 голосов
/ 14 октября 2010

Я вызываю метод, который возвращает переменную List, которая содержит объекты анонимного типа c #. Например:

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!

Ответы [ 8 ]

35 голосов
/ 14 октября 2010

Вы не можете вернуть список анонимного типа, это должен быть список 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
Использовать грязное отражение.

4 голосов
/ 14 октября 2010
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), а анонимные типы не могут иметь имен. Вы должны создать неанонимный тип, если хотите его передать. На самом деле анонимные типы не должны использоваться слишком часто, за исключением внутренних запросов.

2 голосов
/ 14 октября 2010

Если у вас есть метод, подобный следующему:

  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);
  }

Он опирается на тот факт (который может измениться!), Что компилятор повторно использует анонимные типы для типов, имеющих одинаковую «форму» (имена и типы свойств).Поскольку ваш «пример» соответствует «форме» типа в методе, этот же тип используется повторно.

Динамические переменные в C # 4 - лучший способ решить эту проблему.

1 голос
/ 14 октября 2010

Вы не можете делать это с анонимными типами.Просто создайте класс / структуру 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 );
}

РЕДАКТИРОВАТЬ: пропущена существенная часть вопроса.Сейчас исправлено.РЕДАКТИРОВАТЬ: изменил ответ еще раз.Смотри выше.

0 голосов
/ 28 октября 2015

список обратно

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;
}
0 голосов
/ 12 декабря 2014

Я знаю, что опоздал на вечеринку, но я кое-что еще изучал и нашел статью , которая отвечает на ваш вопрос.

Можно привести список объектов обратно ванонимный тип.

    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;
    }
0 голосов
/ 16 октября 2010

я бы использовал

allContacts
 .Select(c => new { c.ContactID, c.FullName })
 .ToList()
 .ForEach(c => {
   ...do stuff;
 });

тогда вам вообще не нужно декларировать. я считаю, что чем меньше деклараций, тем меньше точек с запятой, тем меньше ошибок

0 голосов
/ 14 октября 2010

замена объекта на var для каждой конструкции может работать

...