我开始编写一个非常具体的实用程序方法,它基本上搜索一个给定的对象 - “searchObj”代表字段上的TAttribute,如果找到提供的TAttribute,它会使用提供的“updateValue”参数相应地更新该字段。基本上我最需要的是搜索提供的对象时:
1.如果要搜索的提供对象的字段具有TAttribute,并且该字段是提供的“conditionType”参数的List,则根据更新值自行更新它。
2.如果要搜索的提供对象的字段具有TAttribute,并且该字段是“conditionType”参数提供的 NONMATCHING 类型的列表,则继续搜索List 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;
}
答案 0 :(得分: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]);
代替?