简体   繁体   English

无法通过反射设置字段值

[英]Cannot set a field value through reflection

I started to write a very specific utility method, which basically searches a given object - "searchObj" for a TAttribute over a field and if it finds the provided TAttribute it updates that field accordingly with a provided "updateValue" parameter. 我开始写一个非常具体的实用程序方法,该方法基本上是在给定对象-“ searchObj”上搜索字段上的TAttribute,如果找到了提供的TAttribute,它将使用提供的“ updateValue”参数相应地更新该字段。 Basically what i mostly need is when searching the provided object: 基本上,我最需要的是在搜索提供的对象时:

1.If the field of the provided object to search has the TAttribute and that field is a List of a provided "conditionType" parameter, to update it self accordingly to the update value. 1.如果提供的要搜索对象的字段具有TAttribute,并且该字段是提供的“ conditionType”参数的列表,则将其自身更新为更新值。

2.If the field of the provided object to search has the TAttribute and that field is a List of NONMATCHING type provided by the "conditionType" parameter, to continue searching that List ONLY for a field that matches the condition type and finally if it finds that specific field, to modify the List to be the size of the "updateValue" list by adding or removing elements from it and only modify that field which matches the type critteria. 2.如果提供的要搜索对象的字段具有TAttribute并且该字段是“ conditionType”参数提供的NONMATCHING类型的列表, 继续在该列表中搜索与条件类型匹配的字段,最后找到该特定字段,可以通过在列表中添加或删除元素来将List修改为“ updateValue”列表的大小,并且仅修改与critteria类型匹配的字段。

So for number 1 it worked out easy. 因此,对于第一名,它很容易实现。 The problem which i face is commented out with exclamation signs inside the code sample. 我所面对的问题已在代码示例内用感叹号注释掉了。 Basically the non matching list i try to access and modify the field does not set it's values. 基本上,我尝试访问和修改该字段的不匹配列表未设置其值。 They stay the same as they were never modified. 它们保持不变,因为它们从未被修改过。 What am i doing wrong? 我究竟做错了什么?

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

This is the line you mark with exclamation marks, and the line above it: 这是您用感叹号标记的行,及其上方的行:

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

I don't see the point of doing markedList[index].GetType() to return the type of the newly-created object added to markedList . 我看不到有做markedList[index].GetType()返回添加到markedList的新创建对象的类型的markedList You already know what type this is going to be, it's genericArgument . 您已经知道它将是哪种类型,它是genericArgument

So, let's apply that simplification to the second of your two lines of code above: 因此,让我们将简化应用于上面两行代码的第二行:

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

Clearly now your code is doing nothing with markedList[index] . 显然,您的代码现在对markedList[index] Did you perhaps want 你也许想要

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

instead? 代替?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM