Преобразование анонимного типа в класс

У меня есть анонимный тип внутри List anBook:

var anBook=new []{

new {Code=10, Book ="Harry Potter"},
new {Code=11, Book="James Bond"}
};

Можно ли преобразовать его в список со следующим определением clearBook:

public class ClearBook
{
  int Code;
  string Book; 
}

с помощью прямого преобразования, т. е. без зацикливания на anBook?


person Graviton    schedule 15.01.2009    source источник


Ответы (4)


Ну, вы могли бы использовать:

var list = anBook.Select(x => new ClearBook {
               Code = x.Code, Book = x.Book}).ToList();

но нет, прямой поддержки конвертации нет. Очевидно, вам нужно будет добавить средства доступа и т. д. (не делайте поля общедоступными) - я думаю:

public int Code { get; set; }
public string Book { get; set; }

Конечно, другой вариант — начать с данных так, как вы хотите:

var list = new List<ClearBook> {
    new ClearBook { Code=10, Book="Harry Potter" },
    new ClearBook { Code=11, Book="James Bond" }
};

Есть также вещи, которые вы могли бы сделать для сопоставления данных с отражением (возможно, используя Expression для компиляции и кэширования стратегии), но это, вероятно, не стоит того.

person Marc Gravell    schedule 15.01.2009

Как говорит Марк, это можно сделать с помощью деревьев отражений и выражений... и, как назло, в MiscUtil, который делает именно это. Однако, если посмотреть на ваш вопрос более внимательно, кажется, что вы хотите применить это преобразование к коллекции (массиву, списку или чему-то еще) без цикла. Это не может работать. Вы конвертируете из одного типа в другой — вы не можете использовать ссылку на анонимный тип, как если бы это была ссылка на ClearBook.

Чтобы привести пример того, как работает класс PropertyCopy, вам просто нужно:

var books = anBook.Select(book => PropertyCopy<ClearBook>.CopyFrom(book))
                                 .ToList();
person Jon Skeet    schedule 15.01.2009
comment
Разве CLR не может вывести тип и имя свойства и выполнить автоматическое преобразование? .Net 4.0 должен улучшить это - person Graviton; 15.01.2009
comment
Так что мне не нужно объявлять тип самому. - person Graviton; 15.01.2009
comment
Я не могу сказать, что видел большой спрос на это, и в целом это кажется плохой идеей. - person Jon Skeet; 15.01.2009
comment
Использование его для интеграционных тестов на JsonResult из контроллера MVC - person SkeetJon; 15.04.2016

А как насчет этих расширений? просто вызовите .ToNonAnonymousList для вашего анонимного типа..

public static object ToNonAnonymousList<T>(this List<T> list, Type t)
    {
        //define system Type representing List of objects of T type:
        Type genericType = typeof (List<>).MakeGenericType(t);

        //create an object instance of defined type:
        object l = Activator.CreateInstance(genericType);

        //get method Add from from the list:
        MethodInfo addMethod = l.GetType().GetMethod("Add");

        //loop through the calling list:
        foreach (T item in list)
        {
            //convert each object of the list into T object by calling extension ToType<T>()
            //Add this object to newly created list:
            addMethod.Invoke(l, new[] {item.ToType(t)});
        }
        //return List of T objects:
        return l;
    }
    public static object ToType<T>(this object obj, T type)
    {
        //create instance of T type object:
        object tmp = Activator.CreateInstance(Type.GetType(type.ToString()));

        //loop through the properties of the object you want to covert:          
        foreach (PropertyInfo pi in obj.GetType().GetProperties())
        {
            try
            {
                //get the value of property and try to assign it to the property of T type object:
                tmp.GetType().GetProperty(pi.Name).SetValue(tmp, pi.GetValue(obj, null), null);
            }
            catch (Exception ex)
            {
                Logging.Log.Error(ex);
            }
        }
        //return the T type object:         
        return tmp;
    }
person Christian Casutt    schedule 31.12.2010
comment
В вашем ToType<T>() вам нужно сделать: var value = GetProperty(obj.GetType(), pi.Name).GetValue(obj, null); и GetProperty(typeof(T), pi.Name).SetValue(tmp, value, null); (иначе вы пытаетесь использовать геттер tmp на obj, что не сработает) - person Philip Atz; 10.02.2021

Самый простой способ сделать это — использовать какой-либо метод сериализации.

что-то вроде этих строк

class ClearBook
{
   public int Code { get; set; }
   public string Book { get; set; }
}

ClearBook[] newList = JsonSerializer.Deserialize<ClearBook[]>(JsonSerializer.Serialize(anBook));
person Kyle Thomson    schedule 17.01.2021
comment
А где тут List‹ClearBook›? - person Serge; 17.01.2021