0

Is there a way to generate the class definition of an dynamic object?

  • Without using an online tool like this

For ex:

dynamic test = new System.Dynamic.ExpandoObject();
test.property1 = "test";
test.property2 = 123;

to

public class test
{
   string property1;
   int property2;
}

My usecase involves parsing a file which contains name type and value (simply put) and generating a c# class from that. I had two choices here, storing name and type as strings or using a dynamic object, which seemed more fitting. The class definition of this object should then be generated into c# code.

Edit: Serialization might have been the wrong word - generation fits more nicely

Daniel
  • 99
  • 8
  • 4
    Firstly, calling it "serialisation" isn't really correct. What you're really trying to do is a form of [duck typing](https://stackoverflow.com/questions/4205130/what-is-duck-typing) which isn't really possible in C#. However, you could serialise to a JSON string and then deserialise into the new class. Having said that, this is a really odd requirement, why do you even have a dynamic object in the first place? `dynamic` is bad, and every time you use it, a kitten dies. – DavidG Jan 10 '22 at 18:33
  • Serialization is what I want tho - converting a dynamic object into a class defintion which can be copied / saved. Ps: As for dynamic - it has its place and saying it is bad without giving context is bad, everytime someone says that, a kitten dies. – Daniel Jan 10 '22 at 18:41
  • 2
    No, it's still not serialisation, that is when you convert an object into a stream of bytes or string, which is not what you are doing here. I think the word you are looking for is `casting`. As for dynamic, I would bet that it's absolutely not needed in the first place, it's almost never useful and is often the cause of runtime errors, and is horribly slow. – DavidG Jan 10 '22 at 18:45
  • Why? Because this kinda makes me think of code generators in C# but it really depends on why you want to do this. – Nikki9696 Jan 10 '22 at 18:48
  • Maybe I wasnt clear with that. I do not need the class during runtime. My usecase involves parsing a file which contains name type and value (simply put) into a c# class. For this I am using a dynamic object to build the object which should then be serialized into the c# class and saved as a file – Daniel Jan 10 '22 at 19:03
  • So you're trying to create a source generator for a class described by a dynamic object? – Tech Inquisitor Jan 10 '22 at 19:20
  • You could parse the object's properties into a code string then use [System.Runtime.CompilerServices](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices?view=net-6.0) and compile it. – djv Jan 10 '22 at 20:12
  • I feel you wrongly explanation the problem .... Do you have a Json file, and you try to get the content of it as a C# strong type object ?.... [Read this answer could help you](https://stackoverflow.com/a/67696264/9482050) ... also I would mention that **Visual Studio** since 2012 could do exactly what your [online tool](https://json2csharp.com/) do read [JSON to C# class conversion using Paste Special in Visual Studio](https://www.matthewproctor.com/json-to-c-sharp-class-using-paste-special/) – Ibram Reda Jan 11 '22 at 02:38

2 Answers2

2

you could make a runtime code-generator like this:

public static string GenerateClass(string className, ExpandoObject eObj)
{
    var sb = new StringBuilder();
    sb.Append("public class ");
    sb.Append(className);
    sb.AppendLine();
    sb.Append("{");
    sb.AppendLine();

    foreach (var property in (IDictionary<String, Object>)eObj)
    {
        sb.Append("    ");
        sb.Append(property.Value.GetType());
        sb.Append(" ");
        sb.Append(property.Key);
        sb.Append(" ");
        sb.Append("{ get; set; }");
        sb.AppendLine();
    }

    sb.Append("}");
    sb.AppendLine();
    return sb.ToString();
}

passing your expando object returns:

public class test
{
    System.String property1 { get; set; }
    System.Int32 property2 { get; set; }
}

usage:

static void Main(string[] args)
{
    dynamic test = new System.Dynamic.ExpandoObject();
    test.property1 = "test";
    test.property2 = 123;

    Console.WriteLine(GenerateClass("test", (ExpandoObject)test));
}

**edit: for nested types, you can do this: **

public static string GenerateClass(string className, ExpandoObject eObj)
{
    var sb = new StringBuilder();
    sb.Append("public class ");
    sb.Append(className);
    sb.AppendLine();
    sb.Append("{");
    sb.AppendLine();

    foreach (var property in (IDictionary<String, Object>)eObj)
    {
        string typeName = property.Value.GetType().Name;

        if (property.Value is ExpandoObject nestedEObj)
        {
            typeName = property.Key;
            sb.AppendLine();
            foreach (string nestedClassLine in GenerateClass(property.Key, nestedEObj).Split(Environment.NewLine))
            {
                sb.Append("    ");
                sb.Append(nestedClassLine);
                sb.AppendLine();
            }
        }

        sb.Append("    ");
        sb.Append(typeName);
        sb.Append(" ");
        sb.Append(property.Key);
        sb.Append(" ");
        sb.Append("{ get; set; }");
        sb.AppendLine();
    }
    sb.Append("}");
    sb.AppendLine();
    return sb.ToString();
}

usage:

    static void Main(string[] args)
    {
        dynamic test = new System.Dynamic.ExpandoObject();
        test.property1 = "test";
        test.property2 = 123;

        dynamic nest = new System.Dynamic.ExpandoObject();
        nest.property1 = "testForNest";
        nest.property2 = 456;

        test.nest = nest;

        Console.WriteLine(GenerateClass("test", (ExpandoObject)test));
    }

produces:

public class test
{
    String property1 { get; set; }
    Int32 property2 { get; set; }

    public class nest
    {
        String property1 { get; set; }
        Int32 property2 { get; set; }
    }

    nest nest { get; set; }
}
Cédric Moers
  • 395
  • 1
  • 10
  • Yeah that basically covers it - I was just hoping that there might be a library built for this already. (Formatting for tons of nesting / subclasses) – Daniel Jan 10 '22 at 19:20
  • I made some edits for nested classes as well. I do not know if a library exists that does this, probably there is. – Cédric Moers Jan 10 '22 at 19:35
0

Well, here is some tricky solution: u can use JSON serialization

using System;
using Newtonsoft.Json;

namespace XY
{
    class MainClass
    {
        public static void Main(string[] args)
        {
            dynamic x = new System.Dynamic.ExpandoObject();
            x.property1 = "sadsa";

            var xy = JsonConvert.DeserializeObject<Test>(JsonConvert.SerializeObject(x));

            Console.WriteLine(xy.property1);
            Console.ReadKey();
        }
    }

    public class Test
    {
        public string property1 { get; set; }
    }
}
Qhori
  • 157
  • 12
  • 1
    the question was a bit unclear, the OP wants to generate a class definition, not deserialize the data into an object. The test class does not exist at compile-time, so this does not work, unfortunately. – Cédric Moers Jan 10 '22 at 19:42