Есть ли способ конвертировать динамический или анонимный объект в строго типизированный объявленный объект?
Если у меня есть динамический объект или анонимный объект, структура которого точно соответствует структуре строго типизированного объекта, существует ли способ .NET для создания типизированного объекта из динамического объекта?
Я знаю, что могу использовать тип LINQ dynamicList.Select(dynamic => new Typed { .... }
, или я могу использовать Automapper, но мне интересно, нет ли чего-то специально для этого?
Ответы
Ответ 1
Вы можете сериализовать в промежуточный формат, просто чтобы десериализовать его сразу после этого. Это не самый элегантный или эффективный способ, но он может выполнить вашу работу:
Предположим, это ваш класс:
// Typed definition
class C
{
public string A;
public int B;
}
А это ваш анонимный экземпляр:
// Untyped instance
var anonymous = new {
A = "Some text",
B = 666
};
Вы можете сериализовать анонимную версию в промежуточный формат, а затем снова десериализовать ее в типизированную версию.
var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
var json = serializer.Serialize(anonymous);
var c = serializer.Deserialize<C>(json);
Обратите внимание, что это теоретически возможно с любым сериализатором/десериализатором (XmlSerializer, двоичная сериализация, другие библиотеки json), если круговая передача симметрична.
Ответ 2
Ваш вопрос сводится к вопросу: могу ли я преобразовать одну типизированную переменную статически в другую типизированную переменную статически (из разных цепочек наследования)? и ответ, очевидно, Нет.
Почему ваш вопрос сводится к указанному выше вопросу?
- Использование динамического типа компилируется с использованием типа Object с отражением.
- Ваш код получает Object в действительности, который (в действительности) содержит значение от одного конкретного статического типа.
Таким образом, на самом деле ваш код имеет дело со статически типизированным значением, назначенным объекту, и обрабатывается как Dynamic во время компиляции. Поэтому единственный случай, когда вы можете преобразовать одно статически типизированное значение в другое [без отражения], - это когда они являются частью одной и той же цепи наследования. В противном случае вы обязательно будете использовать отражение явно (написанное вами) или неявно (написанное MS с использованием Dynamic).
Другими словами, следующий код будет работать, только если значение, назначенное динамическому, является базовым или производным типом Person (изобретенным для примера):
dynamic dPerson = GetDynamicPerson();
Person thePerson = (Person)dPerson;
Это в значительной степени.
Справедливо отметить, что вы можете копировать байты по байтам с небезопасным кодом, обращающимся к адресам памяти (например, на С++), но для меня это не лучше, чем отражение.
Ответ 3
Здесь мы можем преобразовать анонимный объект в словарь
Dictionary<string, object> dict =
obj.GetType()
.GetProperties()
.ToDictionary(p => p.Name, p => p.GetValue(obj, null));
Также вы можете использовать объект LINQ:
List<MyType> items = anonymousType.Select(t => new MyType(t.Some, t.Other)).ToList();
Ответ 4
Если ваш объект наследуется от MarshalByRefObject, вы можете использовать RealProxy.
Другой альтернативой является использование Reflection, но вы можете быть ограничены материалами, не отмеченными виртуальными и/или использующими интерфейсы. Вы также можете скопировать значения, предполагая, что свойства доступны для записи, и пустой конструктор работает для вашего случая.
Фактический ответ на ваш вопрос - нет, нет автоматического способа обработки динамического объекта как определенного типа, если он не является экземпляром этого типа, и нет никакого автоматического средства для копирования значений из динамического/анонимного объект в экземпляр именованного класса.
Время выполнения не имеет представления о том, что происходит в конструкторе, или о том, как класс реализован внутри, поэтому любое такое средство выведет из системы безопасность типа. Весь смысл динамического состоит в том, чтобы разрешить отправку/печать времени утки /etc.
edit: Если я неправильно понял вопрос, дайте мне знать, но я предполагаю, что вы хотите рассматривать динамический объект, как если бы это был экземпляр SomeType.
В моих собственных проектах я использовал класс Object Mapper для этого, где он соответствует именам свойств для доступных для записи свойств и одинаковых или принудительных типов, поэтому, по крайней мере, мне не пришлось писать 10 000 строк шаблона, хотя мой источник не был динамическим, поэтому я использовал Reflection.Emit/DynamicMethod, чтобы значительно ускорить его.