Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cast ExpandoObject to anonymous type

Can I cast ExpandoObject to anonymous type ?

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

Added Later

// This is my entity

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;

Dont think about this middle part.. Purpose of it is another one...

My problem is in Execute() method in LookupExecutable class. I dont know how to create a new instance of TSelection type and assign values to it. This TSelection type is always an anonymous type..

like image 787
Sency Avatar asked Apr 20 '12 07:04

Sency


3 Answers

EDIT: I think this question is a prime example of the XY problem. The correct solution doesn't need to concern itself with ExpandoObject or anonymous types, and it would be most likely wrong if it did.


You're looking at it the wrong way. You don't need to create an instance of an anonymous object, you need to invoke the code that is passed to you in an expression (which may or may not be creating an anonymous object).

If you can create an instance of TEntitySource, then that's simple: Compile() the Expression that you got in Select() and then invoke it for each instance of TEntitySource.

If you can't create TEntitySource, you could still do it by rewriting the Expression (using ExpressionVisitor), so that its input is not TEntitySource, but some type you have. But that would require some work from you.


Original answer:

No, that won't work. That's simply not how casting or anonymous types work in C#.

You can't cast between any two types and expect it to work. Either the object you're casting needs to be the type you're casting to, or one of the two types needs to specify a matching cast operator.

The fact that the target type is an anonymous type doesn't change anything (except that you can't even try to cast to an anonymous type directly, because you can't name it; the way you're using typeof() is wrong).

The fact that the source type is dynamic changes things a bit. But only in that the search for the cast operator is done at runtime, not at compile time, and you can even create the cast operator at runtime (see DynamicObject.TryCast()). But that's it, it doesn't add any “magical” cast operators.

The only way I can imagine something like this working would be if you used a variant of “cast by example” and 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);
}

You could then use it something like this:

var expando = new ExpandoObject();
dynamic dynamicExpando = expando;
dynamicExpando.Foo = "SomeString";
dynamicExpando.Bar = 156;
var result = Convert(expando, new { Foo = "", Bar = 1 });

Note that you can't actually invoke Convert() dynamically (by passing it dynamicExpando), because that would mean it would return dynamic too.

like image 189
svick Avatar answered Oct 27 '22 02:10

svick


Use JavaScriptSerializer to convert the ExpandoObject to any Type as follows:

.....
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;
    }

This should do the job.

like image 41
Minas Avatar answered Oct 27 '22 00:10

Minas


here you have an object madre from an ExpandoObject

        var anoObj = new { name = "testName", email = "testEmail" };

        dynamic expandoObj = new System.Dynamic.ExpandoObject();
        object newObj = expandoObj;

But beware, dynamic objects are very very expensive in resource matters, and what you are asking for does not seem to have any sense. A good aproach for what you are asking in the comments supposing you have to deal with dynamic objects and you want to do something with them:

dynamic expando = new System.Dynamic.ExpandoObject();

var myObj = new Dictionary<string, object>();

myObj["myProperty"] = expando.myProperty;

Any dynamyc object is easily casted to a typed Dicionary.

Hope that helps!

like image 1
David Diez Avatar answered Oct 27 '22 02:10

David Diez