2

Is there anything built into .NET 4.5 that will generate a string C# POCO from a dynamic with all auto-implemented properties?

If not, is there anything built into .NET that will give you (something like a) List<KeyValuePair<string, Type>> so that we can generate a POCO according to the pseudo-code:

foreach (var kvp in list)
{
    builder.AppendFormat("public {0} {1} {{ get; set; }}", kvp.Value, kvp.Key);
}

Finally, are there any well-known libraries that can assist with this sort of very basic code generation?

tacos_tacos_tacos
  • 10,277
  • 11
  • 73
  • 126

2 Answers2

6

You can use compileassemblyfromsource to compile your string,

http://msdn.microsoft.com/en-us/library/system.codedom.compiler.codedomprovider.compileassemblyfromsource(v=vs.110).aspx

        var csc = new CSharpCodeProvider(new Dictionary<string, string>() { { "CompilerVersion", "v4.0" } });
        var cp = new CompilerParameters()
        {
            GenerateExecutable = false,
            GenerateInMemory = true
        };

        cp.ReferencedAssemblies.Add("mscorlib.dll");
        cp.ReferencedAssemblies.Add("System.dll");
        cp.ReferencedAssemblies.Add("System.Core.dll");

        // The string can contain any valid c# code
        // A valid class need to be created with its own properties.
        var s = "public class POCOClass{ public int ID {get {return 1;}} }";

        // "results" will usually contain very detailed error messages
        var results = csc.CompileAssemblyFromSource(cp, s);
        var type = results.CompiledAssembly.GetType("POCOClass");
        var obj = (dynamic)Activator.CreateInstance(type);
        var output = obj.ID;
        // or 
        var output_ = obj.GetType().GetProperty("ID").GetValue(obj, null);

You need to define a class for your properties such as called POCOClass.

EDIT:

public static T CopyObjectFromExpando<T>(this object s) where T : class
        {
            var source = (ExpandoObject)s;
            // Might as well take care of null references early.
            if (source == null)
            {
                throw new ArgumentNullException("s");
            }

            var propertyMap = typeof(T).GetProperties().ToDictionary(p => p.Name.ToLowerInvariant(), p => p);
            var destination = Activator.CreateInstance<T>();
            // By iterating the KeyValuePair<string, object> of
            // source we can avoid manually searching the keys of
            // source as we see in your original code.
            foreach (var kv in source)
            {
                PropertyInfo p;
                if (propertyMap.TryGetValue(kv.Key.ToLowerInvariant(), out p))
                {
                    var propType = p.PropertyType;
                    if (kv.Value == null)
                    {
                        if (!propType.IsNullable() && propType != typeof(string))
                        {
                            // Throw if type is a value type 
                            // but not Nullable<>
                            throw new ArgumentException("not nullable");
                        }
                    }
                    else if (propType.IsEnum)
                    {
                        var enumvalue = Enum.ToObject(propType, kv.Value);
                        p.SetValue(destination, enumvalue, null);
                        continue;
                    }
                    else if (propType == typeof(bool) && kv.Value.GetType() != typeof(bool))
                    {
                        var boolvalue = Convert.ToBoolean(kv.Value);
                        p.SetValue(destination, boolvalue, null);
                        continue;
                    }
                    else if (propType.IsNullable())
                    {
                        var nullType = Nullable.GetUnderlyingType(propType);
                        var value = Convert.ChangeType(kv.Value, nullType);
                        p.SetValue(destination, value, null);
                        continue;
                    }
                    else if (kv.Value.GetType() != propType)
                    {
                        // You could make this a bit less strict 
                        // but I don't recommend it.
                        throw new ArgumentException("type mismatch");
                    }
                    p.SetValue(destination, kv.Value, null);
                }
            }

            return destination;
        }
Sinan AKYAZICI
  • 3,942
  • 5
  • 35
  • 60
  • Upvote because this is awesome and helpful for something else I am doing, but it doesn't answer the question. I was looking for more of a way to reverse-engineer a given `dynamic` but after implementing my own "answer" I realize this question is probably too vague. – tacos_tacos_tacos Apr 20 '14 at 11:32
  • OK then, you can convert a dynamic object to a string build, then you can use this code if I understand correctly. Other way, If you have a type for converting dynamic object such as a POCOClass and if you dont want to convert a dynamic object without using string, I have a helper that can convert a dynamic object to type and I can share with you if you want. – Sinan AKYAZICI Apr 20 '14 at 11:43
  • Sure, I would love to see it – tacos_tacos_tacos Apr 21 '14 at 09:58
1

ImpromptuInterface, open source on Nuget

PM> Install-Package ImpromptuInterface

Has ActLikeProperties

by using ImpromptuInterface

Impromput.ActLikeProperties(dynObj, list.ToDictionary(k=>k.Key,v=>v.Value))

This emits a poco dlr proxy around the dynObj

The intent was to be able to bridge simple dynamic objects (like expando) to old code that uses reflection. But generally it's better to do what ImpromptuInterface's main function, which is wrap dynamic objects with statically declared interfaces.

Mark Cooper
  • 6,738
  • 5
  • 54
  • 92
jbtule
  • 31,383
  • 12
  • 95
  • 128