10

Im trying to use DynamicObject in c#, and I needed an array of dynamic:

var d = new dynamic[];

which works fine.

EDIT : See ExpandoObject below.

But I also like to fill that array with some data with this compressed initialize new syntax:

var d = new dynamic[] { 
  new {
   Name = "Some",
   Number = 1010
  },
  new {
   Name = "Other",
   Number = 2010
  }
 }

But in that case all objects gets the non-dynamic type "object" and a loop through the items will give me an exception:

foreach (dynamic item in d)
{
  @item.Name
  @item.Number
}

Error : 'object' does not contain a definition for 'Name'. I guess I just initialize the array items the wrong way. How to add dynamic objects instead?

EDIT: New content:

I realize "dynamic" does not have the capability to dynamically add properties.

I better be using ExpandoObject which exposes all items in an an internal dictionary as properties. But unfortunately ExpandoObject does not seem to support this nice compressed create syntax, and the compiler complains:

var d = new ExpandoObject[]{
new ExpandoObject(){
    Name="Nnn",
    Number=1080
    }
}

So the answer might just be : it's not possible.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
joeriks
  • 3,382
  • 8
  • 32
  • 42
  • 4
    Are you sure you don't just want an array of an anonymous-type? – Ani Jan 26 '11 at 14:42
  • 1
    Is this in ASP.NET MVC3? – Joshua Rodgers Jan 26 '11 at 14:44
  • 1
    Bear in mind that a `dynamic` _is_ an `object`, just that the C# compiler treats it differently and farms all accesses on `dynamic` off to the DLR – thecoop Jan 26 '11 at 14:44
  • The foreach is using Razor yes. And anonymous type - yes, if it works, I get the same error there - thats when I tried dynamic instead :) – joeriks Jan 26 '11 at 14:51
  • @joeriks: Have you tried an explicit cast on each element of the array? It is a little nasty but it might work. – Jeff Yates Jan 26 '11 at 15:00
  • yes - thanks - see my comment to Snowbear. – joeriks Jan 26 '11 at 17:35
  • I dont get this error at all. Your first code block should work just fine. It is it something very specific to your framework? Like it doesn't work in Razor view of ASP.NET MVC? In normal code that C# is just fine. – nawfal Jul 28 '15 at 06:34
  • As to how to fake object initializer syntax for Expandos, see http://stackoverflow.com/questions/4216309/c-sharp-dynamic-object-initializer-wont-compile, http://stackoverflow.com/questions/5910331/how-can-i-use-collectioninitializer-syntax-with-expandoobject – nawfal Jul 28 '15 at 06:53

3 Answers3

11

Hopefully you do not really need dynamics

class Program
{
    static void Main(string[] args)
    {
        var d = new[]
                    {
                        new
                            {
                                Name = "Some",
                                Number = 1010
                            },
                        new
                            {
                                Name = "Other",
                                Number = 2010
                            }
                    };
        foreach (var item in d)
        {
            string s = @item.Name;
            int n = @item.Number;
            Console.WriteLine("{0} {1}", s, n);
        }
    }
}
Snowbear
  • 16,924
  • 3
  • 43
  • 67
  • Yes, so I thought, and I tried that too - but that gives me the same error. Hmm... – joeriks Jan 26 '11 at 14:49
  • @joeriks - added entire code fragment which I was launching, I do not have any errors. – Snowbear Jan 26 '11 at 14:58
  • @joeriks - if it is related to ASP.Net MVC then probably you should tag the question accordingly. I'm not sure how my answer correlates with Razor behavior. – Snowbear Jan 26 '11 at 15:01
  • Yes - it's indeed related to my context someway. The thing is I send the array as a member of a Page dynamic object. When I - like you - run in one and the same class all is fine. And - the only thing I find differs on the d object between the working code and my real one is that in the working code sample a GetType returns <>f__AnonymousType0`2[System.String,System.String][] but in my real code a GetType returns <>f__AnonymousType1`2[System.String,System.String][]. (Which is also what differs when I perform a ToString on the object). Now does that 1 / 0 do for my object? – joeriks Jan 26 '11 at 17:29
  • I think the problem with the Anonymous type in this case is the same as described here http://tomasp.net/blog/cannot-return-anonymous-type-from-method.aspx - which brings me back to my original question, can I do it in a nice way with dynamic instead? – joeriks Jan 26 '11 at 17:43
  • @joeriks - 1/0 doesn't matter - as far as I know it is just a counter for anonymous classes so they will all have different names. And it means that you already have another anonymous class in your real code. Sorry, can't help you with MVC, hopefully somebody else will. – Snowbear Jan 26 '11 at 19:37
7

I come a bit late but here is what i found about it :

if I can't initialise an ExpandoObject, how about initialising it with a dynamic type ?

so i did the following extension method

    public static ExpandoObject CreateExpando(this object item)
    {

        var dictionary = new ExpandoObject() as IDictionary<string, object>;
        foreach (var propertyInfo in item.GetType().GetProperties())
        {
            dictionary.Add(propertyInfo.Name, propertyInfo.GetValue(item, null));
        }
        return (ExpandoObject)dictionary;
    }

I know it's far from ideal, but it's the best I could achieve for now, it works like this :

var myExpandoObject = new { Name="Alex", Age=30}.CreateExpando();
Edwin de Koning
  • 14,209
  • 7
  • 56
  • 74
Alex
  • 86
  • 1
  • 1
  • Can I use this extension method if my projection is stored in a function? eg: `someQueryable.Select(ReusableProjection().ToExpando())`, where `ReusableProjection` returns this: `Expression>` – sports Feb 24 '15 at 17:59
1

The open source framework Impromptu-Interface has a compressed initialization syntax that works with ExpandoObject.

dynamic @new = Builder.New<ExpandoObject>();

var d = @new.List( 
  @new.Expando(
   Name:"Some",
   Number: 1010
  ),
  @new.Expando(
   Name:"Other",
   Number: 2010
  )
 );
jbtule
  • 31,383
  • 12
  • 95
  • 128