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

问题描述 投票:2回答:2

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

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

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

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

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

"new MyObject() 
{
    Prop1 = "a",
    Prop2 = "b",
    Prop3 = "c"
}"
c# visual-studio initialization auto-generate
2个回答
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;
    }
}

0
投票

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

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

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

© www.soinside.com 2019 - 2024. All rights reserved.