BrunoLM
BrunoLM

Reputation: 100331

How to cast a object to an anonymous type in a different assembly?

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?


Steps to reproduce

  1. Create a website
  2. Create a page (default.aspx) and place a <asp:GridView ID="grid" runat="server" />
  3. In the code behind:

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();
}
  1. Create a Class Library project
  2. Add a file 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

Answers (6)

StriplingWarrior
StriplingWarrior

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

user2150650
user2150650

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

jbtule
jbtule

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

n8wrl
n8wrl

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

Amy B
Amy B

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

jonezy
jonezy

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

Related Questions