将ExpandoObject强制转换为匿名类型

时间:2012-04-20 07:11:04

标签: c# generics anonymous-types 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;

不要考虑这个中间部分。它的目的是另一个......

我的问题出在LookupExecutable类的Execute()方法中。我不知道如何创建TSelection类型的新实例并为其赋值。此TSelection类型始终是匿名类型..

3 个答案:

答案 0 :(得分:4)

编辑:我认为这个问题是XY problem的一个主要例子。正确的解决方案不需要关注ExpandoObject或匿名类型,如果确实存在,则很可能是错误的。


你正在以错误的方式看待它。您不需要创建匿名对象的实例,您需要调用在表达式中传递给您的代码(可能创建或不创建匿名对象)。

如果您可以创建TEntitySource的实例,那么这很简单:Compile()您在Expression中获得的Select(),然后为TEntitySource的每个实例调用它1}}。

如果您无法创建TEntitySource,您仍然可以通过重写Expression(使用ExpressionVisitor)来完成此操作,这样它的输入就不是TEntitySource,而是你有某种类型。但这需要你做一些工作。


原始回答:

不,那不行。这不是铸造或匿名类型如何在C#中工作。

您不能在任何两种类型之间进行转换,并期望它能够正常工作。要投射的对象需要是要投射的类型,或者两种类型中的一种需要指定匹配的强制转换操作符。

目标类型是匿名类型的事实不会改变任何东西(除了你甚至不能尝试直接转换为匿名类型,因为你不能命名它;你使用的方式{ {1}}错了。)

源类型为typeof()的事实稍微改变了一些事情。但只是因为搜索转换操作符是在运行时完成的,而不是在编译时完成的,你甚至可以在运行时创建转换操作符(参见DynamicObject.TryCast())。但就是这样,它并没有增加任何“神奇的”演员。

如果您使用“cast by example”的变体和反射,我能想象出这样的工作的唯一方法是:

dynamic

然后您可以使用以下内容:

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

答案 1 :(得分:4)

使用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;
    }

这应该可以胜任。

答案 2 :(得分:1)

这里你有一个来自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;

任何动态物体都很容易被铸造成打字的Dicionary。

希望有所帮助!