Question

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?

Was it helpful?

Solution

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;
        }

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top