C# 如何将对象强制转换为其他程序集中的匿名类型?

C# 如何将对象强制转换为其他程序集中的匿名类型?,c#,dynamic,.net-4.0,datasource,anonymous-types,C#,Dynamic,.net 4.0,Datasource,Anonymous Types,我有一个GridView,其中我的数据源是: items.Select(i => new { ID = i.ID, Foo = i }).ToList(); 在RowDataBound中,我想访问该对象,但不知道如何强制转换它 grid.RowDataBound += (s, e) => { if (e.Row.RowType == DataControlRowType.DataRow) { dynamic item = e.Row.DataItem

我有一个
GridView
,其中我的
数据源是:

items.Select(i => new { ID = i.ID, Foo = i }).ToList();
RowDataBound
中,我想访问该对象,但不知道如何强制转换它

grid.RowDataBound += (s, e) =>
{
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        dynamic item = e.Row.DataItem as 'what?';
    }
};
如何访问此对象属性


复制步骤
  • 创建网站
  • 创建一个页面(default.aspx)并放置一个
  • 在代码隐藏中:
  • 创建类库项目
  • 添加文件
    FooProvider.cs
  • 代码:

    公共类提供程序
    {
    公共可数元素
    {
    得到
    {
    返回新的int[]{1,2,3}
    .Select(i=>new{ID=i,Foo=i*3});
    }
    }
    }
    
    然后在网站上添加参考


    预期结果:获取匿名对象的ID

    当前结果:

    用户代码未处理RuntimeBinderException

    “对象”不包含“ID”的定义



    反射是唯一的方法吗?

    var item=e.Row.DataItem;不起作用


    您不能创建一个自定义模型类来存储信息,以便对其进行强制转换吗?

    不要使用匿名类型。上课

    public class MyCustomRow
    {
      int ID {get;set;}
      Foo Foo {get;set;}
    }
    

    (wtf?动态?

    我认为你不能。不久前我也遇到过类似的情况,我记得我必须使用符号来引用匿名属性(在您的例子中是ID和Foo)。如果要在RowDataBond中执行更复杂的处理,则必须定义一个类。

    如果使用的是
    动态
    ,则根本不需要强制转换它。只需转换您知道的类型的值

    public class MyCustomRow
    {
      int ID {get;set;}
      Foo Foo {get;set;}
    }
    
    dynamic item = e.Row.DataItem;
    DoSomething((int)item.Foo)
    
    (尽管我同意David B的观点,我更喜欢类型安全的声明类。)

    顺便说一下,有一个技巧可以用于泛型,它可以让你做这样的事情:

    var item = e.Row.DataItem.CastAnonymous(new {ID = 1, Foo = 1});
    DoSomething(item.Foo);
    
    。。。但我认为这是三种选择中最糟糕的

    编辑


    在跨程序集工作时,反射是实现要求的唯一方法。匿名类型总是要保持在单个方法的范围内——这就是为什么不能将它们声明为参数或返回类型。它们使LINQ语句这样的语句不那么乏味,但它们的目的不是将C#变成脚本语言。有什么原因使您坚决反对声明强类型吗?

    您可以使用开源框架将匿名类型强制转换为静态接口,从而允许它在另一个程序集中工作

    Impromptu接口实际上使用与dynamic关键字相同的api,只是它将上下文设置为您在其中声明匿名类型的框架。这样,动态调用将正确解析(因为匿名类型被编译为
    内部

    返回新的int[]{1,2,3}
    .Select(i=>new{ID=i,Foo=i*3}
    .ActLike()).ToList();
    
    为什么不使用DataBinder.Eval()


    强制转换为匿名类型是什么意思?如果您事先不知道对象的类型,您希望如何访问其属性?反射如果你不知道GridView中项目的类型,那么你会如何处理它们?@Jamiere:他知道它是什么类型:他只是没有为它声明一个类。这是一个具有特定签名的匿名类。啊,好吧——实际上很有趣,“var”会允许使用匿名类型的属性吗?我不这么认为,因为DataItem和变量类之间缺少链接。@jamietre:没错<一旦您将对象强制转换为正确的类型,code>var
    就可以工作,但是现在我意识到它们在两个不同的程序集中,无法执行强制转换。DataItem是一个对象
    public virtual object DataItem{get;set;}
    它没有属性
    Foo
    否,
    DataItem
    是一个对象。必须将其强制转换为适当的类型才能使用(正常情况下)。DataItem是一个对象,
    item
    最终成为类型
    object
    。当我访问
    .Foo
    时,它会说
    对象
    没有属性
    Foo
    @BrunoLM:
    实际上是一个
    动态
    ,其底层对象为匿名类型。由于它的
    动态性
    ,您可以说
    item.Foo
    。我只是尝试了一下:它是有效的。我注意到我的问题发生了,因为我有不同的程序集。(添加了更多关于这个问题的信息)@BrunoLM:我想这并不奇怪:即使是具有相同签名的匿名类型,如果它们位于不同的程序集中,它们也是不兼容的。我想说这就是你应该定义一个类的原因。当
    dynamic
    被宣布时,纯粹主义者预见到人们会尝试这样使用它,于是发抖。它有它的用途,但这不是其中之一。我想我要做的是“从数据库中选择任何内容并在单个对象中返回”。感谢您的帮助:)为了使这一点更一般化,当类型仅在代码中的一个位置使用并且不需要通过名称引用时,可以使用匿名类型。你正在做一些按名称引用你的类型的事情,因此你不能使用匿名类型。当然,尼姆兰-我决定不描述为什么在我的回答中不应该尝试使用匿名类型的名称以避免重复。
    var item = e.Row.DataItem.CastAnonymous(new {ID = 1, Foo = 1});
    DoSomething(item.Foo);
    
    return new int[] { 1, 2, 3 }
                .Select(i => new { ID = i, Foo = i * 3 }
                                .ActLike<IMyMadeUpInterface>()).ToList();
    
        grid.RowDataBound += (s, e) =>
        {
            if (e.Row.RowType == DataControlRowType.DataRow)
            {
                var test = DataBinder.Eval(e.Row.DataItem, "Id");
            }
        }