Using LINQ, is it possible to output a dynamic object from a Select statement? If so, how?
Asked Answered
N

3

25

Presently in LINQ, the following compiles and works just fine:

var listOfFoo = myData.Select(x => new FooModel{
     someProperty = x.prop1,
     someOtherProperty = x.prop2
});

public class FooModel{
     public string someProperty  { get; set; };
     public string someOtherProperty  { get; set; };
}

However, the past few versions of .NET/C# have expanded the role of dynamic objects such as the ExpandoObject and I am wondering if there is a way to basically do this:

var listOfFoo = myData.Select(x => new ExpandoObject{
     someProperty = x.prop1,
     someOtherProperty = x.prop2
});

Obviously, I have already tried the code above without success, but it seems like I am missing something.

Norge answered 21/3, 2013 at 18:5 Comment(1)
Simple anonymous type projections are all you need here.Di
C
48

You should be able to create a new anonymous object without any type declared:

var listOfFoo = myData.Select(x => new {
    someProperty = x.prop1,
    someOtherProperty = x.prop2
});
Conant answered 21/3, 2013 at 18:7 Comment(6)
D'oh! Man I feel dumb. Yes, it was this easy. Can accept answer in 6 minutes. Thanks!Norge
@MatthewPatrickCashatt Note that there is nothing dynamic about the object. The object that is defined here is statically typed and even immutable as well. Now if that's suitable for your needs, that's great, but if you really wanted what you asked for in the question, then this isn't it.Incult
Thanks, @Servy. I appreciate your answer as well. What is confusing to me in regards to your comment, however, is that @d_r_w's approach still let's me add dynamic properties to the object. For example, foreach(dynamic item in listOfFoo{ item.someNewProperty = "bar" } works fine. What am I missing?Norge
@MatthewPatrickCashatt Just because it compiles doesn't mean it works. Using dynamic is essentially turning off the compiler (or most of it, anyway) so you're not going to get compile time errors even if the code is not going to work at all at runtime.Incult
As an additional note, by not using the dynamic keyword in your selection of said anonymous object, you can keep the type checking of your compiler, so when you're accessing someProperty or someOtherProperty, the compiler will verify all operations on it are conformant to the type of the property.Conant
My friend, you're mixing concepts. The thing you're proposing is called anonymous object, and is not the same as a dynamic object, maybe it works, but it isn't what it was asked for.Jaquelinejaquelyn
I
13

There is nothing preventing you from using Select to return a collection of ExpandoObject's, you just aren't properly constructing the ExpandoObject. Here's one way:

var listOfFoo = myData.Select(x =>
    {
        dynamic expando = new ExpandoObject();
        expando.someProperty = x.prop1;
        expando.someOtherProperty = x.prop2;
        return (ExpandoObject)expando;
    });
Incult answered 21/3, 2013 at 18:16 Comment(17)
I don't think that will work without converting to an IEnumerable.Police
@MystereMan Converting what to an IEnumerable?Incult
Converting the EF IQueryable (I assume it's not Linq to objects). I don't think the ExpandoObject code will be convertible to SQL, so it would likely generate an EF error. You would have to convert the results to IEnumerable to do it.Police
@MystereMan What makes you think that myData is an IQueryable? There's nothing in the question that seems to indicate that to me. If it is indeed an IQueryable then yes, you'd need to add an AsEnumerable in there to run this on the client side.Incult
In my experience, the vast majority of questions about linq are related to either EF or L2S, there's also nothing in the question to indicate it's L2O's so either assumption is invalid.Police
@MystereMan In my experience, the vast majority of questions about linq are related to either EF or L2S In my experience that's not the case at all. Additionally, when it is being used it's frequently clear through the variable names that the source data is coming from a data context, as you see context.Order, ctx.Data, or else something like that. There's also a responsibility to indicate which query provider is being used, if the question relates to one, whereas it's a question that doesn't apply at all to L2O.Incult
Casting should be to dynamic or skipped: return expando;Canuck
@Canuck The question specifically asked how to get a sequence of ExpandoObjects, not a sequence of dynamic which happened to actually contain expando objects.Incult
@ Servy Yes but with ExpandoObject casting listOfFoo is useless(you can't access someProperty and someOtherProperty that way without additional casting to dynamic)Canuck
@Canuck Of course you can. It's just a dictionary under the hood, and you can access the data as such. Just because you can access the data through dynamic doesn't mean you have to.Incult
No, I can not. It throws compilation error 'ExpandoObject' does not contain a definition for 'someProperty' and no extension method 'someProperty' accepting a first argument of type 'ExpandoObject' could be found (are you missing a using directive or an assembly reference?)Canuck
@Canuck Yes, if you try to access the data as a property, it won't work, because the object doesn't have that property, it's just faking it when using dynamic. Like I said, if you access the data as data in a collection, which is what it is, then it will work just fine.Incult
@ Servy Yes, on the ground that ExpandoObject inherits ICollection<KeyValuePair<string, object>> as well as IDictionary<string, object> and so on but that was not my point. I gave you thumbs up for your answer anyway. :)Canuck
@Canuck No, it wasn't your point it was my point. The OP asked for a sequence of expando objects. You said that getting a sequence of expando objects is useless and that they need to be cast to dynamic to get the data. That's wrong, you don't need to cast it to get the data, that's just one way to get the data.Incult
@ Servy OK, this is one of the ways to get the data, on that I agree and it is incorrect to call it useless, but for me(my opinion) this is the logical/fastest/cleanest way to use the data in listOfFoo(in aspect of writing my code),but I guess that everything depends on the case what listOfFoo is needed for...Canuck
@Canuck Your personal preference may be to use dynamic but the question specifically asked to get a sequence of ExpandoObject objects, which is an entirely reasonable request, even if you personally don't like it, so that's what I provided in an answer.Incult
@ Servy Well... The question is in the title and asks "to output a dynamic object from a Select statement" The code snippet in the description I take it more like pseudo code to express what author intends to do(but this only author can tell). Don't get me wrong man, I don't mean to offend you or anything alike (if so I apologize), only wanted to be helpful with my comments and I do it not for points/badges or to troll your answer, so peace.Canuck
A
0
using (var command = this._context.Database.GetDbConnection().CreateCommand())
        {
            command.CommandText = "select * from persons";
            command.CommandType = CommandType.Text;
            this._context.Database.OpenConnection();
            using (var result = command.ExecuteReader())
            {
                var lst = new List<object>();
                var lstColumns = new UserAccount().GetType().GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).ToList();
                while (result.Read())
                {
                    var newObject = new object();
                    dynamic myobject = new ExpandoObject();
                    IDictionary<string, object> myUnderlyingObject = myobject;
                    for (var i = 0; i < result.FieldCount; i++)
                    {
                        var name = result.GetName(i);
                        var val = result.IsDBNull(i) ? null : result[i];
                        myUnderlyingObject.Add(name, val);
                    }
                    lst.Add(myUnderlyingObject);
                }
                return Ok(lst);
            }
        }
Agretha answered 14/9, 2021 at 13:33 Comment(3)
this is a very complicated solution to a very simple request that was asked and answered almost 10 years ago. To provide a new answer now you should include supportive arguments why this solution is superior to the other existing ones, but here you've gone back to first principals to do in 25 lines of code what you could have done in a single Linq expression?Di
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Aspersion
This is a good starting point. Thank you.Faith

© 2022 - 2024 — McMap. All rights reserved.