是否可以使用值从运行时对象自动生成对象初始化代码?

时间:2016-11-10 09:57:51

标签: c# visual-studio initialization auto-generate

也许是一个长镜头,但如果存在,它会节省我一些时间。

更详细地解释。让我们说我有一个很长的XML文件和一个映射类。在运行测试之前,我想测试内容并更改值。我可以通过编写C#代码来重新构建整个XML结构来初始化该映射类,但我想知道的是 - 我绝对必须这样做吗?

所以基本上我想在运行时将一个大的XML文件解析成一个对象然后我生成初始化代码作为一个字符串我可以粘贴到某个地方。让我们说输入是:

<MyObject>
    <Prop1>a</Prop1>
    <Prop2>b</Prop2>
    <Prop2>c</Prop2>
</MyObject>

我想要一个这样的字符串,例如:

"new MyObject() 
{
    Prop1 = "a",
    Prop2 = "b",
    Prop3 = "c"
}"

2 个答案:

答案 0 :(得分:1)

您可能想要检查此Visual Studio extension

但是,您可以使用下面的代码开始简单。摘自answer。它不适用于非类型对象,但它有帮助。

PS:一旦我提出增强功能,我将更新此代码。

    public class ObjectInitGenerator
{
    public static string ToObjectInitializer(Object obj)
    {
        var sb = new StringBuilder(1024);

        sb.Append("var x = ");
        sb = WalkObject(obj, sb);
        sb.Append(";");

        return sb.ToString();
    }

    private static StringBuilder WalkObject(Object obj, StringBuilder sb)
    {
        var properties = obj.GetType().GetProperties();

        var type = obj.GetType();
        var typeName = type.Name;
        sb.Append("new " + type.Name + " {");

        bool appendComma = false;
        DateTime workDt;
        foreach (var property in properties)
        {
            if (appendComma) sb.Append(", ");
            appendComma = true;

            var pt = property.PropertyType;
            var name = pt.Name;

            var isList = property.PropertyType.GetInterfaces().Contains(typeof(IList));

            var isClass = property.PropertyType.IsClass;

            if (isList)
            {
                IList list = (IList)property.GetValue(obj, null);
                var listTypeName = property.PropertyType.GetGenericArguments()[0].Name;

                if (list != null && list.Count > 0)
                {
                    sb.Append(property.Name + " = new List<" + listTypeName + ">{");
                    sb = WalkList(list, sb);
                    sb.Append("}");
                }
                else
                {
                    sb.Append(property.Name + " = new List<" + listTypeName + ">()");
                }
            }
            else if (property.PropertyType.IsEnum)
            {
                sb.AppendFormat("{0} = {1}", property.Name, property.GetValue(obj));
            }
            else
            {
                var value = property.GetValue(obj);
                var isNullable = pt.IsGenericType && pt.GetGenericTypeDefinition() == typeof(Nullable<>);
                if (isNullable)
                {
                    name = pt.GetGenericArguments()[0].Name;
                    if (property.GetValue(obj) == null)
                    {
                        sb.AppendFormat("{0} = null", property.Name);
                        continue;
                    }
                }

                switch (name)
                {
                    case "Int64":
                    case "Int32":
                    case "Int16":
                    case "Double":
                    case "Float":
                        sb.AppendFormat("{0} = {1}", property.Name, value);
                        break;
                    case "Boolean":
                        sb.AppendFormat("{0} = {1}", property.Name, Convert.ToBoolean(value) == true ? "true" : "false");
                        break;
                    case "DateTime":
                        workDt = Convert.ToDateTime(value);
                        sb.AppendFormat("{0} = new DateTime({1},{2},{3},{4},{5},{6})", property.Name, workDt.Year, workDt.Month, workDt.Day, workDt.Hour, workDt.Minute, workDt.Second);
                        break;
                    case "String":
                        sb.AppendFormat("{0} = \"{1}\"", property.Name, value);
                        break;
                    default:
                        // Handles all user classes, should likely have a better way
                        // to detect user class
                        sb.AppendFormat("{0} = ", property.Name);
                        WalkObject(property.GetValue(obj), sb);
                        break;
                }
            }
        }

        sb.Append("}");

        return sb;
    }

    private static StringBuilder WalkList(IList list, StringBuilder sb)
    {
        bool appendComma = false;
        foreach (object obj in list)
        {
            if (appendComma) sb.Append(", ");
            appendComma = true;
            WalkObject(obj, sb);
        }

        return sb;
    }
}

答案 1 :(得分:0)

我遇到了同样的问题,因为我所有的测试数据都存储为XML。提到的Visual Studio扩展(OmarElabd / ObjectExporter)是个好主意,但我需要在单元测试执行期间的运行时从内存中对象生成C#代码。

这是从原始问题演变而来的: https://www.nuget.org/packages/ObjectDumper.NET/

ObjectDumper.Dump(obj,DumpStyle.CSharp);从变量返回C#初始化代码。如果发现问题,请告诉我,您可能想在github上报告它们。