【问题标题】:Cast ExpandoObject to anonymous type将 ExpandoObject 转换为匿名类型
【发布时间】:2012-05-01 18:37:45
【问题描述】:

我可以将 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 类型始终是匿名类型..

【问题讨论】:

  • 你为什么认为你想做你想做的事?
  • 我想动态创建一个匿名类型并动态为其赋值。
  • @KushanFernando,但为什么呢?你想用它做什么?
  • 这与stackoverflow.com/questions/10240487/…问题有关。但是SO已经关闭了这个问题。如何创建一个始终是匿名类型的泛型类型(TResult)的新实例。以及如何为这个新实例的属性赋值?
  • 即使您可以强制转换为匿名类型,它们始终是只读的...请向我们提供更多信息,了解您的整体情况试图完成——而不是你想完成的方式。

标签: c# generics anonymous-types expandoobject


【解决方案1】:

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


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

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

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


原答案:

不,这行不通。这根本不是 C# 中强制转换或匿名类型的工作方式。

您不能在任何两种类型之间进行转换并期望它起作用。您要转换的对象需要是您要转换到的类型,或者两种类型之一需要指定匹配的转换运算符。

目标类型是匿名类型这一事实并没有改变任何东西(除了你甚至不能尝试直接转换为匿名类型,因为你不能命名它;你使用 @ 的方式987654335@错了)。

源类型为dynamic 的事实稍微改变了一些情况。但只是在运行时而不是编译时搜索转换运算符,您甚至可以在运行时创建转换运算符(请参阅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

【讨论】:

  • 非常感谢 svick。我已经坚持了两个多星期。实际上您的 Convert 方法运行良好..但我不得不删除 where 约束。再次感谢您为理解我的问题所做的努力。
【解决方案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】:

这里有一个来自 ExpandoObject 的对象

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

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

但请注意,动态对象在资源方面非常昂贵,而且您所要求的似乎没有任何意义。假设您必须处理动态对象并且想要对它们做一些事情,那么对于您在 cmets 中提出的问题,这是一个很好的方法:

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

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

myObj["myProperty"] = expando.myProperty;

任何动态对象都可以轻松转换为类型化字典。

希望有帮助!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-04-18
    • 2012-01-20
    • 1970-01-01
    • 2010-11-27
    • 2011-04-19
    • 1970-01-01
    • 2012-01-17
    相关资源
    最近更新 更多