Внедрение 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.

Надеюсь, что это поможет!