-1

I have a Queryable<Foo> and a List<Bar>. I'm already able to map which books are related to which Authors using LINQ.

I would like to use values of the Bar and dynamically add properties to the Foo object as shown below, obviously changing the type to object or dynamic.

Is this possible with LINQ, and if so, how can I do it?

Sample Desired Result (eventually parsed to JSON)

{
    "Id" : 1,
    "Name" : "John Doe",
    "Garden" : 7,
    "Pilot" : 4
}

Sample Classes

public class Foo
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class Bar
{
    public string Title { get; set; }
    public int Count { get; set; }
}
22
  • 7
    Where is relation between author and book? Also structure of your json result is very strange and not very comfortable to work with. I suggest to use array of books. Commented Jan 11, 2017 at 16:43
  • 1
    Why not an array of books instead of properties for each book? Commented Jan 11, 2017 at 16:49
  • 2
    I agree with Sergey, however I'm also confused what you mean about "dynamically add properties to the Author object". Do you mean extend the C# Author class, or add properties to the JSON object? Commented Jan 11, 2017 at 16:50
  • 1
    seems like you can search for something like "ExpandoObject to JSON" patridgedev.com/2011/08/24/… Commented Jan 11, 2017 at 17:04
  • 1
    I mention how to add properties in my answer here: stackoverflow.com/questions/15819720/… which you could of course make use of during whatever linq transform you're performing. Commented Jan 11, 2017 at 17:33

3 Answers 3

2

You can not dynamically add properties to classes. I can see a couple of way you could possibly get the desired result.

Simplest would be to amend you classes as

public class Author
{
    public int Id { get; set; }
    public string Name { get; set; }
    public List<Book> AuthorBooks { get; set; }
}

public class Book
{
    public string Title { get; set; }
    public string Isbn { get; set; }
}

However this would give you a slightly different structure on your JSON

The Other way would be to use an ExpandoObject, providing you are using .net.4.0 or above. ExpandoObject allows you to add properties as it is based off the Dynamic class.

You can get more information here https://blogs.msdn.microsoft.com/csharpfaq/2009/09/30/dynamic-in-c-4-0-introducing-the-expandoobject/

Hope this Helps

Edit

You could try something like this

FooList.ForEach((x) =>
            {
                //Define a new expando
                dynamic NewClass = new ExpandoObject();
                NewClass.Id = x.Id;
                NewClass.Name = x.Name;
                //Get the relating Bar Record
                BarList.Where(b=> b.FooId == x.Id).ToList().ForEach((b) =>
                {
                    NewClass[b.Title] = b.Count;
                });
                //This bit Depends on how you want the Json
                using (TextWriter writer = System.IO.File.CreateText("YourFilepat/Here"))
                {
                    var serializer = new JsonSerializer();
                    serializer.Serialize(writer, NewClass);
                }

            });

The JsonSerializer is from Newtonsoft.Json

Sign up to request clarification or add additional context in comments.

1 Comment

The ExpandObject looks like it could work. Do you have any examples of how this might be done? -- Disregarding the List, and sticking strictly to the original question
1

Have you tried using anonymous types?

var foos = new List<Foo>{
    new Foo{Id = 1, Name = "Grapes of Wrath"},
    new Foo{Id = 2, Name = "Shantaram"}
};

var anonObject = from f in foos
                    select new
                    {
                        Id = f.Id,
                        Name = f.Name,
                        Garden = 6
                    };
var serialized = JsonConvert.SerializeObject(anonObject);
return serialized; //[{"Id":1,"Name":"Grapes of Wrath","Garden":6},
    //{"Id":2,"Name":"Shantaram","Garden":6}]

Mind you that anonymous types cannot cross the function boundary, so you'd have to create your dynamic properties and serialize in the same function.

Alternately, you can just create the new type like this:

public class FooBar
{
    public Foo Foo { get; set; }
    public List<Bar> Bars { get; set; }
}

And this guy can move everywhere, has all the properties you need, won't need to be changed every time you change Foo or Bar, and will cleanly serialize.

6 Comments

I like this and think it could be on the right track, but 'Foo' has a lot of properties that will change over time. I don't want to have to add every new field in the select every time. Additionally, serializing in the same method is not an option
@JacobVoller If the types need to exist in different parts of the app, maybe you need to bite the bullet and create the classes. If this "dynamic" class needs the same properties as Foo or Bar, then just inherit from them, no?
The types dont need to exist in different parts of the app, the propertys/Fields just need to be on an object- which can be dynamic
@JacobVoller In that case you may want to consider returning the anonymous type as a System.Object. It has the properties, and they can be discovered, which is what JsonConvert does. Strong typing is usually preferred for maintenance reasons, but dynamic types are not any stronger than System.Object in that regards.
@JacobVoller I edited my answer because it sounds like you are trying really hard to avoid create the new type, but I share the opinion of other commenters here that the new class is the cleanest solution.
|
0

If you are looking to dynamically add a property to an object this could be a solution.

This is what has worked for me, I also had a concern and it was what happened with those domain objects that had many properties, the maintainability for any changes in the object was absurd, I managed to build an implementation with LINQ - ExpandObject - Reflection, which helped to keep my object dynamic and only add the additional properties that my view logic required.

var expandedModel = FooList.Select(x =>
                    {
                        dynamic expandObject = new ExpandoObject();
                        expandObject.NewProperty= $"PropertyValue";
                        foreach (var property in x.GetType().GetProperties())
                        {
                            ((IDictionary<string, object>)expandObject).Add(property.Name, property.GetValue(x));
                        }
                        return expandObject;
                    }).ToList();

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.