Внедрение ExpandoObject в анонимный тип
Можно ли использовать ExpandoObject для анонимного типа?
var anoObj = new { name = "testName", email = "testEmail" };
dynamic expandoObj = new System.Dynamic.ExpandoObject();
// Here I'm populating the expandoObj with same property names/types in anonymoustype(anoObj)
// Now, how to convert this ExpandoObject to anonymoustype ?
var newObj = (typeof(anoObj)expandoObj); // This doesn't work
Добавлено позже
//Это моя сущность
public class Customer
{
#region Public Properties
[ColumnAttribute(Name = "IdColumn")]
public string Id { get; set; }
[ColumnAttribute(Name = "NameColumn")]
public string Name { get; set; }
[ColumnAttribute(Name = "AddressColumn")]
public string Address { get; set; }
[ColumnAttribute(Name = "EmailColumn")]
public string Email { get; set; }
[ColumnAttribute(Name = "MobileColumn")]
public string Mobile { get; set; }
#endregion
}
//--------------------------------------------- ----------------------------------------
public class LookupService<TEntitySource>
{
public LookupService ()
{
}
public LookupShowable<TEntitySource, TSelection> Select<TSelection>(Expression<Func<TEntitySource, TSelection>> expression)
{
var lookupShowable = new LookupShowable<TEntitySource, TSelection>();
return lookupShowable;
}
}
public class LookupShowable<TEntitySource,TSelection>
{
public LookupShowable()
{
}
public LookupExecutable<TEntitySource, TSelection, TShow> Show<TShow>(Expression<Func<TEntitySource, TShow>> expression)
{
var lookupExecutable = new LookupExecutable<TEntitySource,TSelection,TShow>();
return lookupExecutable;
}
}
public class LookupExecutable<TEntitySource, TSelection, TShow>
{
public TSelection Execute()
{
// Here I want to create a new instance of TSelection and populate values from database and return it.
}
}
//--------------------------------------------- -----------------------------------------
// This is How I want to call this from front end...
var lookupService = new LookupService<Customer>();
var lookupSelection = lookupService.Select(C => new { C.Id, C.Name, C.Mobile }).Show(C => new { C.Id, C.Name}).Execute();
string sID = lookupSelection.Id;
string sName = lookupSelection.Name;
string sMobile = lookupSelection.Mobile;
Не думай об этой средней части. Цель этого еще одна...
Моя проблема заключается в методе Execute() в классе LookupExecutable. Я не знаю, как создать новый экземпляр типа TSelection и присвоить ему значения. Этот тип TSelection всегда анонимный.
Ответы
Ответ 1
EDIT: Я думаю, что этот вопрос является ярким примером проблемы XY. Правильному решению не нужно относиться к ExpandoObject
или анонимным типам, и это было бы, скорее всего, неправильно, если бы это произошло.
Вы смотрите на это неправильно. Вам не нужно создавать экземпляр анонимного объекта, вам нужно вызвать код, который передается вам в выражении (которое может создавать или не создавать анонимный объект).
Если вы можете создать экземпляр TEntitySource
, тогда это просто: Compile()
Expression
, который вы получили в Select()
и затем вызвать его для каждого экземпляра TEntitySource
.
Если вы не можете создать TEntitySource
, вы все равно можете сделать это, переписав Expression
(используя ExpressionVisitor
), чтобы его вход не был TEntitySource
, но какой-то тип у вас есть. Но это потребует некоторой работы от вас.
Оригинальный ответ:
Нет, это не сработает. Это просто не то, как кастинг или анонимные типы работают на С#.
Вы не можете использовать между двумя типами и ожидать, что он будет работать. Либо объект, который вы выполняете, должен быть тем типом, который вы используете, либо один из двух типов должен указать соответствующий оператор расстановки.
Тот факт, что тип-тип является анонимным, ничего не меняет (за исключением того, что вы даже не можете просто применить к анонимному типу напрямую, потому что вы не можете назвать его, как вы используете typeof()
неверно).
Тот факт, что тип источника dynamic
немного изменил ситуацию. Но только в том, что поиск оператора трансляции выполняется во время выполнения, а не во время компиляции, и вы даже можете создать оператор трансляции во время выполнения (см. DynamicObject.TryCast()
). Но это он не добавляет никаких "магических" операторов литья.
Единственный способ, которым я могу представить что-то вроде этой работы, будет, если бы вы использовали вариант "cast by example" и reflection:
public T Convert<T>(ExpandoObject source, T example)
where T : class
{
IDictionary<string, object> dict = source;
var ctor = example.GetType().GetConstructors().Single();
var parameters = ctor.GetParameters();
var parameterValues = parameters.Select(p => dict[p.Name]).ToArray();
return (T)ctor.Invoke(parameterValues);
}
Затем вы можете использовать его примерно так:
var expando = new ExpandoObject();
dynamic dynamicExpando = expando;
dynamicExpando.Foo = "SomeString";
dynamicExpando.Bar = 156;
var result = Convert(expando, new { Foo = "", Bar = 1 });
Обратите внимание: вы не можете динамически вызывать Convert()
(передавая его dynamicExpando
), потому что это означает, что он также вернет dynamic
.
Ответ 2
Используйте JavaScriptSerializer для преобразования ExpandoObject в любой тип следующим образом:
.....
dynamic myExpandoObject = new ExpandoObject();
var result = ConvertDynamic<myType>(myExpandoObject);
.....
public T ConvertDynamic<T>(IDictionary<string, object> dictionary)
{
var jsSerializer = new System.Web.Script.Serialization.JavaScriptSerializer();
var obj = jsSerializer.ConvertToType<T>(dictionary);
return obj;
}
Это должно выполнить эту работу.
Ответ 3
здесь у вас есть объект madre из ExpandoObject
var anoObj = new { name = "testName", email = "testEmail" };
dynamic expandoObj = new System.Dynamic.ExpandoObject();
object newObj = expandoObj;
Но будьте осторожны, динамические объекты очень дороги в вопросах ресурсов, и то, о чем вы просите, похоже, не имеет никакого смысла. Хороший подход к тому, что вы просите в комментариях, предполагая, что вам приходится иметь дело с динамическими объектами, и вы хотите что-то с ними сделать:
dynamic expando = new System.Dynamic.ExpandoObject();
var myObj = new Dictionary<string, object>();
myObj["myProperty"] = expando.myProperty;
Любой объект dynamyc легко накладывается на типизированный Dicionary.
Надеюсь, что это поможет!