I want the ability to grab an anonymous type from my view, that was established by the corresponding controller. According to this article, such an ability becomes possible in C# 4.0 with the 'dynamic' keyword. However, when I try to find an actual example I find answers ranging from it kinda 'is possible' to it kinda 'is not possible.'
In my case, I have a controller creating this:
XElement headings = XElement.Parse(part.TagList);
var items = from heading in headings.Descendants("heading")
select new {
name = heading.Attribute("name").Value,
tags = heading.Attribute("tags").Value,
content = shapeHelper.List() //This is a dynamic object!!!
}; //can I add 'as dynamic;' here????
In short it would be nice if, without a static type, my view could simply reach into the model like this:
#{
//Currently this next line returns an error saying that
//'object' contains no method 'Count'
int foo = Model.items.Count();
//This 'foreach' works.
foreach(dynamic lineItem in Model.items){
//But this does not work. Gives another "'object' has no definition for 'name'"
<p>#lineItem.name</p> }
}
Possible?
Not sure it's exactly what you're looking for, but you could always use the ViewBag:
Controller
ViewBag.Items = from heading in headings.Descendants("heading")
select new {
name = heading.Attribute("name").Value,
tags = heading.Attribute("tags").Value,
content = shapeHelper.List()
};
View
ViewBag.Items.First().content;
Related
Consider the following code:
foreach (Type formType in allFormsToLoopThrough)
{
var nonPriorityForm = _context.Query(formType);
foreach (var nonpriority in nonPriorityForm)
{
var name = nonpriority.GetType().Name;
MyWorkAssignmentDTO form = new MyWorkAssignmentDTO
{
FormName = formType.Name
Id = nonpriority.Id
};
}
}
This snippet is looping thought a list of types.
Each type is taken from the list and passed to a Query function that returns an IQueryable - basically a list of records in a given table in a database that matches the type.
Then for each of the record sets that come back, I want to loop through those and from each create a new instance of MyWorkAssignmentDTO. I am only interested in a form name (which I can get from formType) but I cannot get nonpriority.Id
I know for sure that every nonpriority will have an Id once it is resolved in the loop.
What I can't do is implement this to work at run time.
Can anyone help?
I was able to use the dynamic keyword instead of var. While I lose compile time validation, this gets me over the line when I know for sure there will be an Id.
dynamic nonPriorityForm = _context.Query(formType);
I am creating a list like following:
var result = data.Select(p => new
{
p.FirstName,
p.LastName,
Relationship = p.RelationshipType,
p.TierType,
Gender = p.GenderType,
p.AnnualSalary
});
However, I need to add more properties into each of the array item of result like following
foreach(var property in ListOfAdditionalProperties)
{
// Add property logic
}
Is this possible?
I tried ExpandoObject but was not able to come up with the final result list that I get with the Lambda mentioned on top.
No, it's not possible.
You cannot add more members to a dynamic type after the type has been created.
Think of it as a class declaration. Once the class is declared and compiled it cannot be modified.
You need to use another approach, just like the ones you mention. But yes, that has it's drawbacks in regards to syntax.
This question already has answers here:
Dynamic Object Intellisense
(3 answers)
Closed 8 years ago.
My code is like this
var eventDocs = new List<dynamic>();
foreach (var node in eventtypeNode.GetDescendantNodes())
{
string files = node.GetProperty("document").Value;
eventDocs.Add(new { Id = node.Id, Name = node.Name, CreatedOn = node.CreateDate, Path = files });
}
This works good. Now I am trying to fetch the data out of this dynamic list
foreach (var eventDoc in eventDocs)
{
eventDoc.---- //nothing comes on intellisence
}
Nothing comes on IntelliSense? Am I doing anything wrong?
You won't get anything from Intellisense precisely because you've got a List<dynamic>. You're saying, "I don't know at compile-time what this list will contain. When I access members of the elements, just bind that dynamically at execution-time."
Given that you're deferring binding to execution time, why would you be surprised that Intellisense can't tell what will be in the list?
It looks to me like you should change your code to use a LINQ query to start with - then you can have a list with a known element type, which will be an anonymous type.
var eventDocs = eventtypeNode.GetDescendantsNodes()
.Select(node => new { Id = node.Id,
Name = node.Name,
CreatedOn = node.CreateDate,
Path = node.GetProperty("document").Value })
.ToList();
You cannot access dynamic members like this, try GetDynamicMemberNames() and GetMetaObject method
Intellisense will not show suggestions, since the data is dynamic, and it doesn't know what to show.
But you know what it contains. So just code and you'll be fine.
Also, you don't need dynamic objects here. Since what you want is well-defined just define your class with necessary properties and methods and then create the list:
List<YourClass> list = new List<YourClass>();
And then Intellisense will become intelligent enough to show the suggestions ;)
I'm OK with both C# and VB.NET
I have a function GetListOfBook, that returns LINQ to SQL result that has a collection of objects like the following:
var result = GetListOfBook();
Book is a Book object that property
of Title and ISBN,
Category is a string
Author is an Author object that has
Name and ID property.
So inside the collecton, it looks like this:
So inside the "result" collection it looks like this:
{Book = {Book}, Category = "English", Author = {Author}}
{Book = {Book}, Category = "English", Author = {Author}}
{Book = {Book}, Category = "Web Development", Author = {Author}}
I want to iterate over each item in the collection to get the Book title and ISBN, Category and the author name. Something like this:
foreach (var r in result)
{
Respone.Write(r.Book.Title, r.Book.ISBN, r.Category, r.Auhtor.Name);
}
At the moment, I cannot iterate over the collection yet. Thank you for any suggestion.
Update:
Sorry for the trouble. This is actually working. I found the typo in the code.
You still need to use the correct syntax for foreach which requires you to specify a type for the loop variable. Since you can't name it explicitly, you need to use var which infers the type.
foreach (var r in result)
{
Respone.Write(r.Book.Title, r.Book.ISBN, r.Category, r.Auhtor.Name);
}
You need to use an implicitly typed variable using var for the iteration variable within foreach, just as you presumably have for your query to start with:
var result = ...; // Your existing query
// r is implicitly typed here
foreach (var r in result)
{
Response.Write(r.Book.Title, r.Book.ISBN, r.Category, r.Author.Name);
}
EDIT: Looking more closely at your code, I suspect this is the problem:
var result = GetListOfBook();
This can't be strongly typed, if it's returning an anonymous type... which means it must be returning something like IEnumerable or IEnumerable<object>. I suspect you'll need to create an appropriate "normal" type to contain the results from GetListOfBook - or perform the query in the same method that does the Response.Write call.
you can use reflection like this:
foreach (var r in result)
{
PropertyInfo info = r.GetProperty("Category");
Response.Write(info.GetValue(r, null));
}
You can use reflection to access the anonymous type's properties.
You can see some samples here:
http://blogs.msdn.com/b/wriju/archive/2007/10/26/c-3-0-anonymous-type-and-net-reflection-hand-in-hand.aspx
But you should do it really as a last resort if you MUST use anonymous types rather than explicit types.
[update]
I'm sorry, i should tag this question
as MVC-2, I pass result of query into
view's model, so i must specify type
of my model in View's header
defintion. I declare it like this:
Inherits="System.Web.Mvc.ViewPage<IQueryable<dynamic>>"
how ever nothing changed and none of
answers doesn't work for me :(.
finally i used an ModelView class as
helper to put my query result in it.
:(
[/update]
I have a query like this:
IQueryable<dynamic> result = from d in KiaNetRepository.KiaNetEntities.Discounts
where d.AgentTypeID == agentTypeId
select new { d.Category, d.DiscountValue, d.PriceConfige };
then i retrive value in my view like this:
foreach(var item in result){
Category cat = item.Category; // throws exception 'object' does not contain a definition for 'Category'
//...
}
note that type of query as IQueryable is anonymouse class...
Try to declare names explicitly:
select new { Category = d.Category, DiscountValue = d.DiscountValue, PriceConfige = d.PriceConfige }
If you are not forcing result to be of IQueryeable<dynamic> for any specific reason, I would recommend using var result = .... This will let the compiler make result of type IQueryable<T> with T the type of the anonymous class that you create using new { ... } in the select. There is no necessity for using dynamic from the code that you show here.
If you replace the inappropriate declaration IQueryable<dynamic> by var, sure it works, I've just also tested it.
Your problem is that your foreach loop being in the view page gets compiled into a separate assembly. Since anonymous types are internal the dynamic doesn't see it because of the permissions don't allow it.
Simplest fix is to call ToList() on your query statement and then select each anonymous type and copy parameters to a declared class or expandoobject.