1

I have the following function

 public List<Object> GetEventsForAdmin()
    {
        using (var dbEntities = new CapeledEntities())
        {
            return (from e in dbEntities.Events
                    join lnk in dbEntities.linkEventCategories on e.EventId equals lnk.EventId
                    join cat in dbEntities.Categories on lnk.CategoryId equals cat.CategoryId
                    orderby e.StartDateTime descending
                    select new { 
                                    e.EventId, 
                                    EventTitle =  e.Title,
                                    e.StartDateTime,
                                    e.Description, 
                                    CatTitle = cat.Title 
                   }
            ).ToList<Object>();
        }
    }

I am using

  var eventHelper = new BusinessLogic.DatabaseAccess.Helpers.BLEvents();
  foreach (var myEvent in eventHelper.GetEventsForAdmin())
  {
       txtTitle.text = myEvent.CatTitle;
       txtDescription.text = myEvent.description;
   }

However myEvent.CatTitle and myEvent.description are not found argh

  }
Welsh King
  • 3,178
  • 11
  • 38
  • 60
  • You have returned a list of anonymous types cast as object. The code in the foreach loop has no idea what they are. You can try foreach (dynamic myEvent in...) instead of var. The compiler will accept anything you put after myEvent. , but will complain at runtime if it's not present on the anonymously typed object. – Baldrick Oct 12 '13 at 16:17
  • The actual type of each element in `GetEventsForAdmin` is **anonymous type**, you can't get any access to an object of anonymous type outside its scope. and that's not `dynamic` – King King Oct 12 '13 at 16:20

3 Answers3

2

Change

foreach (var myEvent in eventHelper.GetEventsForAdmin())

to

foreach (dynamic myEvent in eventHelper.GetEventsForAdmin())

This should allow you to access members of an anonymous type which has been cast as an object.

Baldrick
  • 11,712
  • 2
  • 31
  • 35
2

Instead of using dynamic, I'd suggest you create a simple struct or class like this:

class Event
{ 
    public int EventId;
    public string EventTitle;
    public DateTime StartDateTime;
    public string Description;
    public string CatTitle;
}

Now instead of doing select new in your LINQ, you can create a well-defined type that will give you coding advantages as well as performance boost becuz no boxing/unboxing will be involved.

Your LINQ would then be:

public List<Event> GetEventsForAdmin()
{
    using (var dbEntities = new CapeledEntities())
    {
        return (from e in dbEntities.Events
                join lnk in dbEntities.linkEventCategories on e.EventId equals lnk.EventId
                join cat in dbEntities.Categories on lnk.CategoryId equals cat.CategoryId
                orderby e.StartDateTime descending
                select new Event() { 
                                .EventId = e.EventId, 
                                .EventTitle = e.Title,
                                .StartDateTime = e.StartDateTime,
                                .Description = e.Description, 
                                .CatTitle = cat.Title 
               }
        ).ToList();
    }
}
dotNET
  • 33,414
  • 24
  • 162
  • 251
  • Valid point about performance. Also gives added advantage of finding out about typos in the member-accessing code at compile time! – Baldrick Oct 12 '13 at 16:32
  • I agree with your suggestion, but not for the performance reason. It's a compile time vs run-time type checking. See Mark's Comment on http://stackoverflow.com/questions/191013/can-a-c-sharp-anonymous-class-implement-an-interface: "Use of anonymous types should typically be limited to lambda and LINQ expressions... as soon as the data is being exposed to callers that need to "do something" with the object, its a very good idea to implement a concrete class" – Steve Clanton Oct 12 '13 at 16:36
  • Performance reason is as valid as intellisense benefit. This is precisely what Mark's comment you posted actually means. – dotNET Oct 12 '13 at 16:38
1

It seems there are three possible ways as far as I know.

1) Use Dynamic (requires .Net 4.0 or higher)

foreach (dynamic myEvent in eventHelper.GetEventsForAdmin())

2) Create your own type(perhaps a class) instead of anonymous type

3) Third one is a tricky one which uses CastByExample which you can find here

object obj = eventHelper.GetEventsForAdmin();
var events = CastByExample(obj, new[] { 
                                    new { EventId = 0, 
                                          EventTitle = "",
                                          StartDateTime = DateTime.MinValue,
                                          Description = "", 
                                          CatTitle = ""
                                        }
                                      }.ToList());
foreach (var item in events)
{
    Console.WriteLine(item.EventId);
}

private static T CastByExample<T>(object obj, T example)
{
    return (T)obj;
}

4) As @KingKing suggested in comments I missed Reflection you can do that via reflection too, but that's not a good idea to this problem.

Being said that as many methods available, I'll suggest method 2 which is the ideal solution to this problem.

Sriram Sakthivel
  • 72,067
  • 7
  • 111
  • 189