C# 静态递归方法的问题

C# 静态递归方法的问题,c#,reflection,recursion,static,C#,Reflection,Recursion,Static,我正在处理一个逻辑,其中我已经从字典键/值对填充了一个复合类实例。复合类将使用属性进行标记,这些属性将映射到字典中的键。 一个具体要求是,如果类别C1具有类别C2类型的属性,但字典中没有类别C2属性对应的对,则C2应设置为null。否则,如果至少有一个C2属性可以映射,则必须实例化C1的C2属性。 我已经编写了一个递归函数来实现这个逻辑。该要求未按预期工作。我正在使用一个标志isInstanceValuePresent,它检查C2的至少一个属性是否可以映射。否则,它的假值应该告诉我必须将null

我正在处理一个逻辑,其中我已经从字典键/值对填充了一个复合类实例。复合类将使用属性进行标记,这些属性将映射到字典中的键。 一个具体要求是,如果类别C1具有类别C2类型的属性,但字典中没有类别C2属性对应的对,则C2应设置为null。否则,如果至少有一个C2属性可以映射,则必须实例化C1的C2属性。 我已经编写了一个递归函数来实现这个逻辑。该要求未按预期工作。我正在使用一个标志isInstanceValuePresent,它检查C2的至少一个属性是否可以映射。否则,它的假值应该告诉我必须将null赋值给类C1的C2属性。如果有人能帮助我理解为什么逻辑会失败,以及什么是正确的解决方案,我将非常感激。以下是静态递归方法:

/// <summary>
    /// Populates the given instance object with the supplied source dictionary values
    /// </summary>
    /// <param name="modelInstance">The object whose properties are to be initialized with the data</param>
    /// <param name="source">The source dictionary containing Schema(Keys) and corresponding Values</param>
    private static void PopulateModelInstance(object modelInstance, IDictionary<string, string> source)
    {
        bool isInstanceValuePresent = false;

        foreach (PropertyInfo propInfo in modelInstance.GetType().GetProperties())
        {
            //Identify Custom attribute 
            DataMappingKeyAttribute attribute = (DataMappingKeyAttribute)Attribute.GetCustomAttribute(propInfo, typeof(DataMappingKeyAttribute));

            if (attribute != null && !string.IsNullOrEmpty(attribute.MappingKey))
            {
                if (propInfo.PropertyType.IsPrimitive || propInfo.PropertyType.Equals(typeof(string)))
                {
                    string sourceKey = attribute.MappingKey;

                    if (source.ContainsKey(sourceKey))
                    {
                        isInstanceValuePresent = true;

                        // Get propInfo attribute value from Dictionary
                        //var propertySourceValue = source[(propInfo.PropertyType.GetCustomAttribute(typeof(DataMappingKeyAttribute)) as DataMappingKeyAttribute).MappingKey];
                        string sourceValue = source[attribute.MappingKey];

                        // Set propInfo value on the model instance
                        if (CanChangeType(sourceValue, propInfo.PropertyType) && propInfo.CanWrite && (!propInfo.PropertyType.IsClass || propInfo.PropertyType.Equals(typeof(string))))
                            propInfo.SetValue(modelInstance, Convert.ChangeType(sourceValue, propInfo.PropertyType), null);
                    }
                }
            }


            if (propInfo.PropertyType.IsClass && !propInfo.PropertyType.Equals(typeof(string)) && propInfo.CanWrite)
            {
                isInstanceValuePresent = false;
                object referenceTypeInstance = Activator.CreateInstance(propInfo.PropertyType);

                PopulateModelInstance(referenceTypeInstance, source);

                if (isInstanceValuePresent == false)
                {
                    propInfo.SetValue(modelInstance, null, null);
                    referenceTypeInstance = null;
                }
                else
                {
                    propInfo.SetValue(modelInstance, referenceTypeInstance, null);
                }
            }
        }
    }
//
///用提供的源字典值填充给定的实例对象
/// 
///要使用数据初始化其属性的对象
///包含架构(键)和相应值的源字典
私有静态void PopulateModelInstance(对象模型实例,IDictionary源)
{
布尔值isInstanceValuePresent=假;
foreach(modelInstance.GetType().GetProperties()中的PropertyInfo-propInfo)
{
//标识自定义属性
DataMappingKeyAttribute=(DataMappingKeyAttribute)属性.GetCustomAttribute(propInfo,typeof(DataMappingKeyAttribute));
if(attribute!=null&&!string.IsNullOrEmpty(attribute.MappingKey))
{
if(propInfo.PropertyType.IsPrimitive | | propInfo.PropertyType.Equals(typeof(string)))
{
字符串sourceKey=attribute.MappingKey;
if(source.ContainsKey(sourceKey))
{
isInstanceValuePresent=真;
//从字典中获取propInfo属性值
//var propertySourceValue=source[(propInfo.PropertyType.GetCustomAttribute(typeof(DataMappingKeyAttribute))作为DataMappingKeyAttribute.MappingKey];
字符串sourceValue=source[attribute.MappingKey];
//在模型实例上设置propInfo值
if(CanChangeType(sourceValue,propInfo.PropertyType)和&propInfo.CanWrite&(!propInfo.PropertyType.IsClass | | propInfo.PropertyType.Equals(typeof(string)))
SetValue(modelInstance,Convert.ChangeType(sourceValue,propInfo.PropertyType),null);
}
}
}
if(propInfo.PropertyType.IsClass&&!propInfo.PropertyType.Equals(typeof(string))&&propInfo.CanWrite)
{
isInstanceValuePresent=假;
对象引用类型实例=Activator.CreateInstance(propInfo.PropertyType);
PopulateModelInstance(referenceTypeInstance,source);
如果(isInstanceValuePresent==false)
{
SetValue(modelInstance,null,null);
referenceTypeInstance=null;
}
其他的
{
SetValue(modelInstance,referenceTypeInstance,null);
}
}
}
}

代码的一个主要问题是变量的使用isInstanceValuePresent。在递归调用PopulateModelInstance之前,将变量设置为false,然后在方法返回后测试该值。不幸的是,这个变量是一个局部变量,驻留在堆栈上,因此对于每个调用都是局部的。它不会反映递归调用中设置的值

我有一个建议,你可以如何改变你的方法。您可以传入要填充的对象的类型,而不是传入要填充的对象。使用已经实现的相同逻辑,只有在找到可以设置的属性值时,才会实例化此类型的对象。然后,该方法传回实例。如果未找到要设置的属性,则该方法将传回null

private static Object CreateAndPopulateModelInstance(Type modelInstanceType, IDictionary<string, string> source)
{
    // this variable will hold the reference to the instance that is to be
    // populated. It will only hold a value, if a property is found that
    // can be populated.
    Object modelInstance = null;

    foreach (PropertyInfo propInfo in modelInstanceType.GetProperties())
    {
        //Identify Custom attribute 
        DataMappingKeyAttribute attribute =  DataMappingKeyAttribute)Attribute.GetCustomAttribute(propInfo, typeof(DataMappingKeyAttribute));

        if (attribute != null && !string.IsNullOrEmpty(attribute.MappingKey))
        {
            if (propInfo.PropertyType.IsPrimitive || propInfo.PropertyType.Equals(typeof(string)))
            {
                string sourceKey = attribute.MappingKey;

                if (source.ContainsKey(sourceKey))
                {
                    // Get propInfo attribute value from Dictionary
                    //var propertySourceValue = source[(propInfo.PropertyType.GetCustomAttribute(typeof(DataMappingKeyAttribute)) as DataMappingKeyAttribute).MappingKey];
                    string sourceValue = source[attribute.MappingKey];

                    // Set propInfo value on the model instance
                    if (CanChangeType(sourceValue, propInfo.PropertyType) && propInfo.CanWrite && (!propInfo.PropertyType.IsClass || propInfo.PropertyType.Equals(typeof(string))))
                    {
                        // create instance if necessary
                        if (modelInstance == null)
                            modelInstance = Activator.CreateInstance(modelInstanceType);

                        propInfo.SetValue(modelInstance, Convert.ChangeType(sourceValue, propInfo.PropertyType), null);
                    }
                }
            }
        }
        else if (propInfo.PropertyType.IsClass && !propInfo.PropertyType.Equals(typeof(string)) && propInfo.CanWrite)
        {
            Object propertyValue = CreateAndPopulateModelInstance(propInfo.PropertyType, source);
            if (propertyValue != null)
            {
                // create instance if necessary
                if (modelInstance == null)
                    modelInstance = Activator.CreateInstance(modelInstanceType);

                // set property value
                propInfo.SetValue(modelInstance, propertyValue, null);
            }
        }
    }

    return modelInstance;
}

希望这能有所帮助。

如果有人能帮我优化功能,我甚至很感激。逻辑怎么会失败?它是否没有执行,或者您的结果如何不符合预期?感谢@roadkill,您的解决方案工作得非常好。我真的很感谢你为解释解决方案所做的努力。
private static Object CreateAndPopulateModelInstance(Object instance, Type modelInstanceType, IDictionary<string, string> source)
{
    // this variable will hold the reference to the instance that is to be
    // populated. It will only hold a value, if a property is found that
    // can be populated.
    Object modelInstance = instance;
            Object propertyValue = CreateAndPopulateModelInstance(null, propInfo.PropertyType, source);
            if (propertyValue != null)
            {