tags:

views:

1010

answers:

5

Using the C# object initializer syntax I can instantiate an anonymous object like this:

object empData = new { name = "bob", age = 30, salary = 100000 };

But what if I have the initializer stored in a string, e.g.:

string init = "{ name = \"bob\", age = 30, salary = 100000 }";

Whats the best way of converting this string into an instance of the object?

+1  A: 

There's no direct easy way to do so. Basically, you have these options:

  1. Parse the string manually.
  2. Use the C# compiler to compile that object as a part of an assembly and use reflection to figure out the contents.
  3. (not sure if it's possible, C# 4.0 only): Use C# 4.0 managed compiler classes to parse the expression and infer the stuff.

None of which is ideal in my opinion. I'd consider QueryString like pairs, XML or JSON or some other format that has parsers available out there instead if you have the option and consider storing data in a dictionary instance instead of creating an object for every expression.

Mehrdad Afshari
+5  A: 

It's not possible using anonymous types, however you can do it with Reflection Emit using the TypeBuilder class, specifically TypeBuilder.Create(..).

http://msdn.microsoft.com/en-us/library/system.reflection.emit.typebuilder.createtype.aspx

BFree
+1  A: 

I don't think this question answers yours per se, but it will tell you why it's not possible to create anonymous instances of objects using strings in a manner such as you suggest:

http://stackoverflow.com/questions/478013/how-do-i-create-and-access-a-new-instance-of-an-anonymous-class-passed-as-a-param

Anonymous types don't have any public fields, consequently while you can do this for a named object, it's not so simple to do it for an anonymous type. That said, there's nothing to stop you [as suggested by BFree] using reflection to emit the MSIL for the anonymous type - which isn't exactly straightforward, but isn't impossible either.

BenAlabaster
+1  A: 

The best way to do it is to use serialization. But of course, that doesn't use the same string format that you described.

Your object initializer does not have to contain constant values.

string myName="bob";
int myAge=30;
double mySalary=100000;

object empData = new { name = myName, age = myAge, salary = mySalary };

So in your scenario you would have to parse out the individual elements from your string, and perform some conversions on them to coerce them into the types you want.

If you are not married to this particular string format, you can serialize and deserialize your objects and accomplish the same thing using XML much more easily.

Robert Harvey
+1 for thinking outside the confines of the question... it must be getting late
BenAlabaster
+4  A: 

Anonymous classes are C# syntactic sugar (see Remarks section here). csc.exe creates a class with private fields and a read/write property with the type inferred from context. All uses of the object are, again, inferred.

What this means is you cannot create an anonymous class at run time because the CLR sees them no differently than any other class (again, because it is C# syntactic sugar).

So instead:

  • Use a Dictionary<string,object>
  • Use JSON.NET, XML or something like it that has some already-defined scheme for parsing a string to get an object. This requires the properties be well-defined, however.
  • Use System.Reflection.Emit to create the type at run-time, but I see no real benefit to this over just a Dictionary<string,object>

I also have concerns of what you're doing because this as a string very likely means to me that you are accepting user input of some kind. Be wary of the security issues in whatever you do.

Colin Burnett
Argh... you're right, I knew about anon classes being generated at compile time but my brain didn't make the connection (guess the long weekend is overdue). Also your concern about security and user input is definitely valid. Anyway, the reason I was doing this is because the API I was calling took an anonymous object. But it turns out I can also pass in a Dictionary<string, object> so that solves the problem for me. Thanks.
DSO