[英]How to cast a object to an anonymous type in a different assembly?
我有一个GridView
,我的DataSource
是:
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?';
}
};
如何访问此对象属性?
<asp:GridView ID="grid" runat="server" />
添加
protected void Page_Load(object sender, EventArgs ev)
{
var provider = new FooProvider();
grid.DataSource = provider.Elements;
grid.RowDataBound += (s, e) =>
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
dynamic item = e.Row.DataItem;
var test = item.ID;
}
};
grid.DataBind();
}
FooProvider.cs
代码:
public class FooProvider
{
public IEnumerable<dynamic> Elements
{
get
{
return new int[] { 1, 2, 3 }
.Select(i => new { ID = i, Foo = i * 3 }).ToList();
}
}
}
然后在网站上添加参考。
预期结果:获取匿名对象的 ID。
当前结果:
用户代码未处理 RuntimeBinderException
“object”不包含“ID”的定义
反思是唯一的方法吗?
不要使用匿名类型。 做一堂课。
public class MyCustomRow
{
int ID {get;set;}
Foo Foo {get;set;}
}
(wtf?动态的?)
如果您使用的是dynamic
,则根本不需要投射它。 只需转换您知道类型的值。
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# 成为一种脚本语言。 您是否有理由坚决反对声明强类型?
编辑 2
几年过去了,我们已经有了一些无需使用匿名类型的轻量级类型选项。
记录允许您使用一行代码进行类声明:
public record FooElement(int ID, int Foo);
public IEnumerable<FooElement> Elements
{
get
{
return new int[] { 1, 2, 3 }
.Select(i => new FooElement(i, i * 3)).ToList();
}
}
var item = (FooElement) e.Row.DataItem;
var test = item.ID;
如果你真的不想创建一个命名类来表示你的返回类型,你可以使用 ValueTuple 语法:
public IEnumerable<(int ID, int Foo)> Elements
{
get
{
return new int[] { 1, 2, 3 }
.Select(i => (i, i * 3)).ToList();
}
}
var item = ((int ID, int Foo)) e.Row.DataItem;
var test = item.ID;
或者
var (test, _) = ((int, int)) e.Row.DataItem;
为什么不使用 DataBinder.Eval() ?
grid.RowDataBound += (s, e) =>
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
var test = DataBinder.Eval(e.Row.DataItem, "Id");
}
}
var item = e.Row.DataItem; 不工作?
你不能创建一个自定义模型类来存储信息以便你可以转换它吗?
我不认为你可以。 不久前我也遇到过类似的事情,我记得我不得不使用 <% %> 表示法来引用匿名属性(在你的例子中是 ID 和 Foo)。 如果您在 RowDataBound 中有更复杂的处理要做,则必须定义一个类。
您可以使用开源Impromptu-Interface框架将匿名类型强制转换为静态接口,使其可以在另一个程序集中工作。
Impromptu 接口实际上使用与 dynamic 关键字相同的 api,只是它将上下文设置为您在其中声明匿名类型的框架。这样动态调用将正确解析(因为匿名类型被编译为internal
)。
return new int[] { 1, 2, 3 }
.Select(i => new { ID = i, Foo = i * 3 }
.ActLike<IMyMadeUpInterface>()).ToList();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.