从C#中的动态生成POCO

时间:2014-04-18 03:09:00

标签: c# dynamic reflection code-generation poco

.NET 4.5中是否有内容可以从具有所有自动实现属性的dynamic生成字符串C#POCO?

如果没有,.NET中是否有任何内容可以为您提供(类似于)List<KeyValuePair<string, Type>>,以便我们可以根据伪代码生成POCO:

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

最后,是否有任何知名的库可以帮助进行这种非常基本的代码生成?

2 个答案:

答案 0 :(得分:5)

您可以使用compileassemblyfromsource来编译字符串,

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

您需要为您的属性定义一个类,例如名为POCOClass。

修改

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

答案 1 :(得分:1)

ImpromptuInteface,Nuget上的开源

PM> Install-Package ImpromptuInterface

ActLikeProperties

using ImpromptuInterface

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

这会在dynObj

周围发出一个poco dlr代理

目的是能够将简单的动态对象(如expando)桥接到使用反射的旧代码。但通常最好是使用ImpromptuInterface的主要功能,即使用静态声明的接口包装动态对象。