将ExpandoObject转换为匿名类型

14
我能将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类型总是一个匿名类型...

2
你为什么认为你想做的是正确的? - Ramesh
1
我想动态创建一个匿名类型并动态地为其赋值。 - Sency
1
@KushanFernando,但是为什么?你想用它做什么? - svick
1
即使您可以将其转换为匿名类型,它们始终是只读的...请向我们提供有关您尝试实现的更大背景的更多信息 - 而不是您考虑实现它的方式。 - Jon Skeet
显示剩余3条评论
3个回答

10

编辑: 我认为这个问题是XY问题的一个典型例子。正确的解决方案不需要涉及ExpandoObject或匿名类型,如果涉及这些,很可能是错误的。


你的思路是错误的。你不需要创建一个匿名对象的实例,你需要调用在表达式中传递给你的代码(可能会或可能不会创建匿名对象)。

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

如果你不能创建TEntitySource,你仍然可以通过重写Expression(使用ExpressionVisitor)来实现,使其输入不是TEntitySource,而是一些你拥有的类型。但这需要你付出一些努力。


原始答案:

不,那样行不通。这不是在C#中转换或匿名类型的工作方式。

你不能在任何两个类型之间进行强制转换并期望它可以工作。要么需要强制转换的对象是你要转换到的类型,要么这两种类型中的一种需要指定匹配的强制转换运算符。

目标类型是匿名类型并不改变任何事情(除了你甚至无法直接尝试将其强制转换为匿名类型,因为你无法命名它; 你使用typeof()的方式是错误的)。

源类型是dynamic这个事实有点改变了。但只是在运行时而不是编译时搜索强制转换运算符,并且您甚至可以在运行时创建强制转换运算符(参见DynamicObject.TryCast())。但仅此而已,它并没有添加任何“神奇”的强制转换运算符。

我唯一能想象出类似这样的东西可以工作的方式是,如果你使用“按示例强制转换”和反射的变体:

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

请注意,您实际上不能通过动态传递dynamicExpando来调用Convert(),因为这意味着它也将返回dynamic

非常感谢你,svick。我已经卡在这里两个多星期了。实际上,你的“Convert”方法运行良好...但我不得不删除where限制。再次感谢您理解我的问题所付出的努力。 - Sency

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

这应该能完成工作。

4
他所寻找的并不是“任何类型”,而是具体指向“匿名类型”。 - sports

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;

任何动态对象都可以轻松地转换为一个类型的字典。
希望有所帮助!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接