Приведение 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 всегда анонимный тип..

3 ответов


EDIT: я думаю, что этот вопрос является ярким примером XY проблема. Правильное решение не должно беспокоиться о ExpandoObject или анонимные типы, и было бы, скорее всего, неправильно, если бы это было так.


вы смотрите на это неправильно. Вам не нужно создавать экземпляр анонимного объекта, вам нужно вызвать код, который передается вам в выражении (которое может или не может создавать анонимный объект.)

если вы можете создать экземпляр TEntitySource, тогда это просто:Compile() the Expression что ты попал в Select() и затем вызвать его для каждого экземпляра TEntitySource.

если вы не можете создать TEntitySource, вы все еще можете сделать это путем переписывания Expression (через ExpressionVisitor), так что его ввод не TEntitySource, но какой-то тип у вас есть. Но это потребует от вас некоторой работы.


Оригинал ответ:

нет, это не сработает. Это просто не то, как кастинг или анонимные типы работают в C#.

вы не можете бросить между любыми двумя типами и ожидать, что он будет работать. Либо объект, который вы бросаете, должен быть типом, к которому вы бросаете, либо один из двух типов должен указать соответствующий оператор приведения.

тот факт, что целевой тип является анонимным типом, ничего не меняет (за исключением того, что вы даже не можете попытаться привести к анонимному типу непосредственно, потому что вы не можете назвать его; то, как вы используете typeof() - это неправильно).

тот факт, что тип Источник dynamic немного меняет ситуацию. Но только в том случае, если поиск оператора cast выполняется во время выполнения, а не во время компиляции, и вы даже можете создать оператор cast во время выполнения (см. DynamicObject.TryCast()). Но это все, он не добавляет никаких "магических" операторов.

единственный способ, которым я могу представить себе что-то вроде этого, - это использовать вариант "cast by example" и размышления:

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 тоже.


используйте 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;
    }

Это должно сделать работу.


здесь у вас есть объект 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.

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