Reputation: 100331
I have a GridView
where my DataSource
is:
items.Select(i => new { ID = i.ID, Foo = i }).ToList();
In the RowDataBound
I want to access the object, but I don't know how to cast it...
grid.RowDataBound += (s, e) =>
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
dynamic item = e.Row.DataItem as 'what?';
}
};
How can I access this object properties?
<asp:GridView ID="grid" runat="server" />
add
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
Code:
public class FooProvider
{
public IEnumerable<dynamic> Elements
{
get
{
return new int[] { 1, 2, 3 }
.Select(i => new { ID = i, Foo = i * 3 }).ToList();
}
}
}
Then add the reference on the website.
Expected result: Get the ID of the anonymous object.
Current result:
RuntimeBinderException was unhandled by user code
'object' does not contain a definition for 'ID'
Is reflection the only way?
Upvotes: 2
Views: 3696
Reputation: 156524
If you're using dynamic
you don't need to cast it at all. Just cast the values that you know the type of.
dynamic item = e.Row.DataItem;
DoSomething((int)item.Foo)
(Though I agree with David B that I'd rather have a type safe, declared class.)
And by the way, there is a trick you can use with generics which would allow you to do something like this:
var item = e.Row.DataItem.CastAnonymous(new {ID = 1, Foo = 1});
DoSomething(item.Foo);
... but I think that's the worst of the three options.
Edit
When working across assemblies, reflection is the only way to do what you're asking. Anonymous types were always intended to stay within the confines of a single method--that's why you can't declare them as a parameter or a return type. They make things like LINQ statements far less tedious, but their purpose is not to make C# into a scripting language. Is there a reason that you're dead-set against declaring a strong type?
Edit 2
Several years on now, we've got some lightweight type options available without using anonymous types.
Records allow you to do a class declaration with a single line of code:
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;
And if you really don't want to create a named class to represent your return type, you can use ValueTuple syntax:
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;
or
var (test, _) = ((int, int)) e.Row.DataItem;
Upvotes: 4
Reputation: 1
Why not use DataBinder.Eval() ?
grid.RowDataBound += (s, e) =>
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
var test = DataBinder.Eval(e.Row.DataItem, "Id");
}
}
Upvotes: 0
Reputation: 31799
You can use the opensource Impromptu-Interface framework to duck cast an anonymous type to a static interface allowing it to work in another assembly.
Impromptu interface is actually using the the same api as the dynamic keyword except that it sets the context to the framework you declared your anonymous type in. That way the dynamic invocation will resolve properly (since anonymous types are compiled as internal
).
return new int[] { 1, 2, 3 }
.Select(i => new { ID = i, Foo = i * 3 }
.ActLike<IMyMadeUpInterface>()).ToList();
Upvotes: 0
Reputation: 19765
I don't think you can. I had something similar going on a while back and as I recall i had to use <% %> notation to refer to the anonymous properties (ID and Foo, in your case). If you have more complex processing to do in your RowDataBound you'll have to define a class.
Upvotes: 0
Reputation: 110111
Don't use anonymous types. Make a class.
public class MyCustomRow
{
int ID {get;set;}
Foo Foo {get;set;}
}
(wtf? dynamic?)
Upvotes: 7
Reputation: 1923
var item = e.Row.DataItem; doesn't work?
can you not create a custom model class to store the information so that you can cast it?
Upvotes: 0