2015-02-08 67 views
0

我開始編寫一個非常特定的實用程序方法,它基本上搜索給定對象 - 「searchObj」以獲取字段上的TAttribute,並且如果它找到提供的TAttribute,則相應地使用提供了「updateValue」參數。基本上我最需要的是在搜索提供的對象時:無法通過反射設置字段值

1.如果提供的要搜索的對象的字段具有TAttribute,並且該字段是提供的「conditionType」參數的列表,則相應地將其自身更新爲更新值。

2.如果所提供的對象搜索領域具有TAttribute那場是由「conditionType」參數設置不匹配的列表,繼續搜索該列表ONLY的匹配字段條件類型,最後如果它找到特定的字段,通過添加或刪除元素來修改List爲「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; 
} 

回答

1

這是你用感嘆號標記線,以及它上面的一行:

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

我看不出做markedList[index].GetType()返回新創建的對象的類型的點添加到markedList。你已經知道這將是什麼類型,它是genericArgument

所以,我們認爲簡化適用於上述代碼的兩行的第二個:

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

顯然現在你的代碼是什麼都不做與markedList[index]。您是否想要

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

取而代之?

+0

對!鷹眼! – 2015-02-08 15:25:36