I have an object created by - new {name1 = "string1"}
I have to add additional members to it eg {name2 = "string2"} so that the final result is
{
name1 = "string1",
name2 = "string2"
}
You can either instantiate it all at once:
var someObj = new {name1 = "name 1", name2 = "name 2"};
Or you can do it in steps.
var someObj1 = new {name1 = "name 1"};
var someObj2 = new {name1 = someObj1.name1, name2 = "name 2"};
But no, you can't add properties/field to anonymous types at run-time or after it's been instantiated.
You have to create a new object, of a new anonymous type:
var obj1 = new {name1 = "string1"};
var obj2 = new {name1 = obj1.name1, name2 = "string2" };
Related
I have a function in which i am getting data(array of objects) from db and then adding those objects of array one by one into a lit of type ExpandoObject
public async Task<List<ExpandoObject>> GetGroupWithMaxTickets(){
List<ExpandoObject> topGroupsWithMaxTickets = new List<ExpandoObject>();
dynamic ticketDetails = new ExpandoObject();
var pipeline_tickets = new BsonDocument[]{
new BsonDocument("$match",
new BsonDocument
{
{ "nsp", "/sbtjapan.com" },
{ "datetime",
new BsonDocument
{
{ "$gte", "2019-12-03T00:00:34.417Z" },
{ "$lte", "2019-12-03T24:00:34.417Z" }
} }
}),
new BsonDocument("$group",
new BsonDocument
{
{ "_id", "$group" },
{ "totalTIckets",
new BsonDocument("$sum", 1) }
}),
new BsonDocument("$project",
new BsonDocument
{
{ "_id", 0 },
{ "group", "$_id" },
{ "totalTIckets", 1 }
}),
new BsonDocument("$sort",
new BsonDocument("totalTIckets", -1)),
new BsonDocument("$limit", 5)
};
var collection = await DbService.tickets.AggregateAsync<RawBsonDocument>(pipeline_tickets, new AggregateOptions {UseCursor = true, BatchSize = 500});
await collection.MoveNextAsync();
if(collection.Current.ToList().Count > 0){
// ticketDetails = JsonConvert.DeserializeObject(collection.Current.ToJson());
// ticketDetails.group = collection.Current.ToList()[0]["group"];
// ticketDetails.totalTickets = collection.Current.ToList()[0]["totalTIckets"];
Parallel.ForEach(collection.Current.ToList(), (ticket) => {
Console.WriteLine("Ticket----"+ticket);
dynamic groupWithTickets = new ExpandoObject();
groupWithTickets = ticket;
topGroupsWithMaxTickets.Add(groupWithTickets);
});
}
return topGroupsWithMaxTickets;
}
But it throws an error like this
System.AggregateException: One or more errors occurred. (The best overloaded method match for 'System.Collections.Generic.List<System.Dynamic.ExpandoObject>.Add(System.Dynamic.ExpandoObject)' has some invalid arguments)
I want that my function must return array of objects of type List<ExpandoObject>
How can i do this in c#?
Since you have changed the question, following is the answer that should resolve your matters.
How to NOT work with ExpandoObjects
I tested this on my system and got it to reproduce the same results as you are getting. Following is the failed try:
dynamic employee = new ExpandoObject();
List<ExpandoObject> listOfEmployees = new List<ExpandoObject>();
employee = "someStrangeString";
listOfEmployees.Add(employee); // ERROR !!!!
and just as expected, i get the following error on Add.
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException
HResult=0x80131500
Message=The best overloaded method match for 'System.Collections.Generic.List.Add(System.Dynamic.ExpandoObject)' has some invalid arguments
Source=
StackTrace:
Corrected way of ExpandoObject use
Following is the method that will take care of the issues with Adding it to the list.
Parallel.ForEach(collection.Current.ToList(), (ticket) =>
{
Console.WriteLine("Ticket----" + ticket);
dynamic groupWithTickets = new ExpandoObject();
groupWithTickets.users = ticket; //<---- Assign ticket to users element.
topGroupsWithMaxTickets.Add(groupWithTickets);
});
What was done to fix it?
When you are working with ExpandoObjects, you have to think of dictionary type of a deal. When you declare ExpandoObject, you have to dynamically assign the value to an element (that you define).
Example from MS site: shows the proper use of ExpandoObject
dynamic employee, manager;
employee = new ExpandoObject();
employee.Name = "John Smith";
employee.Age = 33;
manager = new ExpandoObject();
manager.Name = "Allison Brown";
manager.Age = 42;
manager.TeamSize = 10;
Hopefully this resolves your issue.
It should be like this;
dynamic ticketDetails = new ExpandoObject();
ticketDetails.user = collection;
string json = Newtonsoft.Json.JsonConvert.SerializeObject(ticketDetails);
You can simply do this:
dynamic ticketDetails = new ExpandoObject();
ticketDetails = Json(new users = JsonConvert.DeserializeObject(collection.Current.ToJson()));
For testing purposes, i used an array arr that holds one of the elements. If you need that array to be part of ExtendoObject with first element being users, you can create a Json object and set the array as value to the "users" element.
dynamic ticketDetails = new ExpandoObject();
JArray arr = new JArray();
arr.Add(#"[{""name"": ""Alex"", ""age"": 21}]");
JObject o = new JObject();
o["users"] = arr.ToString();
ticketDetails = o;
// output: { "users" : [{"name" : "Alex", "age" : 21}]}
please tell me, how do I get the json like this:
dynamic packet = new ExpandoObject();
packet.type = "somethink";
packet.user = 12345;
packet.nets[0].amout = 123;
packet.nets[0].lower = 0;
packet.nets[1].amout = 345;
packet.nets[1].lower = 1;
string input = Newtonsoft.Json.JsonConvert.SerializeObject(packet);
Its not workig, error:
An unhandled exception of type "Microsoft.CSharp.RuntimeBinder.RuntimeBinderException" in System.Core.dll
For more information: "System.Dynamic.ExpandoObject" does not contain definitions of "nets"
Thanks.
It's the ExpandoObject who's a dynamic object. The rest of properties should be other ExpandoObject instances or regular objects, arrays, collections...
For example:
packet.nets = new[]
{
new { amount = 123, lower = 0 },
new { amount = 345, lower = 1 }
}
Or:
packet.nets = new[]
{
new Dictionary<string, int> { { "amount", 345 }, { "lower", 0 } },
new Dictionary<string, int> { { "amount", 123 }, { "lower", 1 } }
}
There're many other approaches, including the use of instances of concrete classes.
Firstly, you need create nets in packet object, like this:
packet.nets = new dynamic[2];
And initialize the objects in nets, if you want with `ExpandoObject too:
packet.nets[0] = new ExpandoObject();
packet.nets[1] = new ExpandoObject();
Then is done, complete code:
dynamic packet = new ExpandoObject();
packet.type = "somethink";
packet.user = 12345;
packet.nets = new dynamic[2];
packet.nets[0] = new ExpandoObject();
packet.nets[0].amout = 123;
packet.nets[0].lower = 0;
packet.nets[1] = new ExpandoObject();
packet.nets[1].amout = 345;
packet.nets[1].lower = 1;
string input = Newtonsoft.Json.JsonConvert.SerializeObject(packet);
You first need to declare nets. For example
packet.nets = new Dictionary<int, dynamic>();
Then you'll need to instantiate the instances of nets
packet.nets[0] = new {amount = 123, lower = 0};
The result being
dynamic packet = new ExpandoObject();
packet.type = "somethink";
packet.user = 12345;
packet.nets = new Dictionary<int, dynamic>();
packet.nets[0] = new { amount = 123, lower = 0 };
packet.nets[1] = new { amount = 345, lower = 1 };
Given the following code, I'd like to select all "parties" at some position in the array:
var f1 = new Filing();
var f2 = new Filing();
var f3 = new Filing();
var f4 = new Filing();
var p1 = new Party() {Name = "p1"};
var p2 = new Party() { Name = "p2" };
var p3 = new Party() { Name = "p3" };
var p4 = new Party() { Name = "p4" };
var p5 = new Party() { Name = "p5" };
var p6 = new Party() { Name = "p6" };
var p7 = new Party() { Name = "p7" };
var p8 = new Party() { Name = "p8" };
var p9 = new Party() { Name = "p9" };
var p10 = new Party() { Name = "p10" };
var p11 = new Party() { Name = "p11" };
var p12 = new Party() { Name = "p12" };
var p1List = new List<Party>();
p1List.Add(p1);
p1List.Add(p2);
p1List.Add(p3);
f1.Parties = p1List;
var p2List = new List<Party>();
p2List.Add(p4);
p2List.Add(p5);
p2List.Add(p6);
f2.Parties = p2List;
var p3List = new List<Party>();
p3List.Add(p7);
p3List.Add(p8);
p3List.Add(p9);
f3.Parties = p3List;
var p4List = new List<Party>();
p4List.Add(p10);
p4List.Add(p11);
p4List.Add(p12);
f4.Parties = p4List;
var fList = new List<Filing>();
fList.Add(f1);
fList.Add(f2);
fList.Add(f3);
fList.Add(f4);
What I want is to get a list of all Parties in the 0th position for all Filings... example would return p1, p4, p7, and p10. I tried:
fList.SelectMany(f => f.Parties[0]);
...but get a compilation error stating that SelectMany cannot be inferred from the usage. Any ideas?
SelectMany assumes that its argument will return an IEnumerable. Your argument returns a single object; therefore a simple Select is more appropriate than a SelectMany.
Alt1
var yourValues = fList.SelectMany(x => x.Parties.Take(1)).Select(s =>
s.Name);
Alt2
var yourValues = fList.Select(x => x.Parties.First().Name);
foreach (var val in yourValues)
{
Console.WriteLine(val); //p1 p4 p7 p10
}
I am trying to do something like:
Object [] x = new Object[2];
x[0]=new Object(){firstName="john";lastName="walter"};
x[1]=new Object(){brand="BMW"};
I want to know if there is a way to achieve that inline declaration in C#
yes, there is:
object[] x = new object[2];
x[0] = new { firstName = "john", lastName = "walter" };
x[1] = new { brand = "BMW" };
you were practically there, just the declaration of the anonymous types was a little off.
You can also declare 'x' with the keyword var:
var x = new
{
driver = new
{
firstName = "john",
lastName = "walter"
},
car = new
{
brand = "BMW"
}
};
This will allow you to declare your x object inline, but you will have to name your 2 anonymous objects, in order to access them. You can have an array of "x" :
x.driver.firstName // "john"
x.car.brand // "BMW"
var y = new[] { x, x, x, x };
y[1].car.brand; // "BMW"
You can also do this:
var x = new object[] {
new { firstName = "john", lastName = "walter" },
new { brand = "BMW" }
};
And if they are the same anonymous type (firstName and lastName), you won't need to cast as object.
var y = new [] {
new { firstName = "john", lastName = "walter" },
new { firstName = "jill", lastName = "white" }
};
I'm trying to build a Dynamics CRM 4 query so that I can get calendar events that are named either "Event A" or "Event B".
A QueryByAttribute doesn't seem to do the job as I cannot specify a condition where the field called "event_name" = "Event A" of "event_name" = "Event B".
When using the QueryExpression, I've found the FilterExpression applies to the Referencing Entity. I don't know if the FilterExpression can be used on the Referenced Entity at all. The example below is something like what I want to achieve, though this would return an empty result set as it will go looking in the entity called "my_event_response" for a "name" attribute. It's starting to look like I will need to run several queries to get this but this is less efficient than if I can submit it all at once.
ColumnSet columns = new ColumnSet();
columns.Attributes = new string[]{ "event_name", "eventid", "startdate", "city" };
ConditionExpression eventname1 = new ConditionExpression();
eventname1.AttributeName = "event_name";
eventname1.Operator = ConditionOperator.Equal;
eventname1.Values = new string[] { "Event A" };
ConditionExpression eventname2 = new ConditionExpression();
eventname2.AttributeName = "event_name";
eventname2.Operator = ConditionOperator.Equal;
eventname2.Values = new string[] { "Event B" };
FilterExpression filter = new FilterExpression();
filter.FilterOperator = LogicalOperator.Or;
filter.Conditions = new ConditionExpression[] { eventname1, eventname2 };
LinkEntity link = new LinkEntity();
link.LinkCriteria = filter;
link.LinkFromEntityName = "my_event";
link.LinkFromAttributeName = "eventid";
link.LinkToEntityName = "my_event_response";
link.LinkToAttributeName = "eventid";
QueryExpression query = new QueryExpression();
query.ColumnSet = columns;
query.EntityName = EntityName.mbs_event.ToString();
query.LinkEntities = new LinkEntity[] { link };
RetrieveMultipleRequest request = new RetrieveMultipleRequest();
request.Query = query;
return (RetrieveMultipleResponse)crmService.Execute(request);
I'd appreciate some advice on how to get the data I need.
The QueryExpression object has a Criteria property that you can set. If you're looking for "my_event" records that have name A or name B, just set it up like this:
ColumnSet columns = new ColumnSet();
columns.Attributes = new string[]{ "event_name", "eventid", "startdate", "city" };
ConditionExpression eventname1 = new ConditionExpression();
eventname1.AttributeName = "event_name";
eventname1.Operator = ConditionOperator.Equal;
eventname1.Values = new string[] { "Event A" };
ConditionExpression eventname2 = new ConditionExpression();
eventname2.AttributeName = "event_name";
eventname2.Operator = ConditionOperator.Equal;
eventname2.Values = new string[] { "Event B" };
FilterExpression filter = new FilterExpression();
filter.FilterOperator = LogicalOperator.Or;
filter.Conditions = new ConditionExpression[] { eventname1, eventname2 };
QueryExpression query = new QueryExpression();
query.ColumnSet = columns;
query.EntityName = EntityName.mbs_event.ToString();
query.Criteria = filter;
RetrieveMultipleRequest request = new RetrieveMultipleRequest();
request.Query = query;
return (RetrieveMultipleResponse)crmService.Execute(request);
If you're only looking for events that have responses, keep the LinkEntity part in, but move the FilterExpression over to the QueryExpression object like I have above.