无法通过反射设置字段值

Cannot set a field value through reflection

我开始编写一个非常具体的实用程序方法,它基本上搜索给定对象 - "searchObj" 在字段上查找 TAttribute,如果它找到提供的 TAttribute,它会相应地使用提供的 "updateValue" 参数。基本上我最需要的是在搜索提供的对象时:

1.If 提供的要搜索对象的字段具有 TAttribute,该字段是提供的 "conditionType" 参数的列表,根据更新值自行更新。

2.If 提供的要搜索对象的字段具有 TAttribute,并且该字段是由 "conditionType" 参数提供的 NONMATCHING 类型的列表,继续在列表 ONLY 中搜索与条件类型匹配的字段,最后如果找到该特定字段,则将列表修改为 "updateValue" 列表的大小在其中添加或删除元素,并且仅修改与类型条件匹配的字段。

所以对于 1 号来说,结果很容易。我面临的问题在代码示例中用感叹号注释掉了。基本上,我尝试访问和修改字段的非匹配列表不会设置它的值。它们保持不变,因为它们从未被修改过。我做错了什么?

/// <summary>
/// Updates all object fields marked with TAtrribute with the provided value. 
/// The attribute field generic argument must meet the condition type in order the values to be correctly updated.
/// </summary>
/// <typeparam name="TAttribute">The attribute to search for</typeparam>
/// <param name="obj">The actual object which will be searched for the attribute</param>
/// <param name="updateValue">The provided value must be a List<conditionType></param>
public static void UpdateAttributeMarkedField<TAttribute>(object searchObj, object updateValue, Type conditionType) where TAttribute : Attribute
{
    Type valueType = updateValue.GetType();
    Type objectType = searchObj.GetType();

    // Get all the public and instance fields from the object
    List<FieldInfo> objectFields = objectType.GetFields(BindingFlags.Instance | BindingFlags.Public).ToList();

    // Search all fields and return the ones marked with the [TAttruibute] attribute as list.
    List<FieldInfo> markedFields = GetAttributeMarkedField<TAttribute>(objectFields);

    for (int i = 0; i < markedFields.Count; i++)
    {
        IList valueList = null;

        if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(List<>))
        {
            valueList = (IList)updateValue;
        }

        // Make sure we only accept lists both for the "obj" and the "value" arguments
        if (markedFields[i].FieldType.IsGenericType && markedFields[i].FieldType.GetGenericTypeDefinition() == typeof(List<>) && valueList != null)
        {
            Type genericArgument = markedFields[i].FieldType.GetGenericArguments()[0];

            // If the marked field is of type List<conditionType> simply just update the values
            if (genericArgument == conditionType)
            {
                markedFields[i].SetValue(searchObj, updateValue);
            }

            // If the marked field is some other type of list, 
            // search for the condition type and if there is one, update it with the provided "value" list.
            else
            {
                FieldInfo[] fields = genericArgument.GetFields();

                bool meetsCondition = false;
                string fieldName = String.Empty;

                // If any marked field meets the condition type get the field name
                for (int j = 0; j < fields.Length; j++)
                    if (fields[j].FieldType == conditionType)
                    {
                        meetsCondition = true;
                        fieldName = fields[j].Name;
                    }

                if (meetsCondition == true)
                {
                    IList markedList = (IList)markedFields[i].GetValue(searchObj);

                    // If the marked list is smaller than the provided value list resize it accordingly by adding the difference.
                    if (markedList.Count < valueList.Count)
                    {
                        int difference = valueList.Count - markedList.Count;

                        for (int j = 0; j < difference; j++)
                        {
                            int index;
                            index = markedList.Add(Activator.CreateInstance(genericArgument));

                            // Update the freshly created field from the condition type to match the freshly created value list
                            // !!!!!!!! DOES NOT SET THE FIELD VALUE !!!!!!!
                            markedList[index].GetType().GetField(fieldName).SetValue(searchObj, valueList[index]);
                        }

                    }

                    // If the marked list is bigger than the provided value list, resize it accordingly by removing the difference.
                    else if (markedList.Count > valueList.Count)
                    {

                    }

                }

            }
        }
        else
        {
            Debug.LogWarning(@"Currently only lists are supported for the ""obj"" and ""value"" arguments. Skipping update for: " + markedFields[i].GetType());
        }

    }

}

public static List<FieldInfo> GetAttributeMarkedField<TAttribute>(List<FieldInfo> searchContext) where TAttribute : Attribute
{
    List<FieldInfo> result = new List<FieldInfo>();
    for (int i = 0; i < searchContext.Count; i++)
        if (Attribute.IsDefined(searchContext[i], typeof(TAttribute)))
        {
            result.Add(searchContext[i]);
        }
    return result;
}

这是您用感叹号标记的行,以及它上面的行:

index = markedList.Add(Activator.CreateInstance(genericArgument));
markedList[index].GetType().GetField(fieldName).SetValue(searchObj, valueList[index]);

我看不出 markedList[index].GetType() 到 return 添加到 markedList 的新创建对象的类型有什么意义。您已经知道这将是什么类型,它是 genericArgument.

因此,让我们将该简化应用于上面两行代码中的第二行:

genericArgument.GetField(fieldName).SetValue(searchObj, valueList[index]);

很明显,现在您的代码对 markedList[index] 没有任何作用。你也许想要

genericArgument.GetField(fieldName).SetValue(markedList[index], valueList[index]);

代替?