C# - 在复杂的 class 层次结构中查找具有特定名称属性的所有对象
C# - find all objects which has attribute with specific name, in complex class hierarchy
我有一个复杂的 class 层次结构:class B 是 class A 的属性,List(class C) 和 class D 是class B 等的属性 - 很多级别的父子关系。
层次结构中的某些 class 具有字符串属性 "foobar"。有些 classes 没有。
我有一个 class A 的实例。我需要在层次结构中找到所有具有属性 "foobar" 的对象,并将其值更改为 "qwerty"。
在 C# 中是否有一种简单的方法来做到这一点?
public class ClassD
{
public string fooBar;
}
public class ClassC
{ }
public class ClassB
{
public List<ClassC> classCList;
public ClassD classDInstance;
public string fooBar;
}
public class ClassA
{
public ClassB classBInstance;
}
您似乎想更改具有给定名称的属性的值。
这很丑陋,但可能会让您了解如何使用 reflection 完成您想要的事情:
static void Set<T>(dynamic obj, string property, T value) {
//Iterate through the fields on your object. Can change this to properties or do both.
foreach (var field in obj.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance)) {
var fieldValue = field.GetValue(obj);
//If we have a collection, then iterate through its elements.
if (field.FieldType.GetInterface("System.Collections.IEnumerable") != null && !(fieldValue is string) && fieldValue != null)
foreach (var item in fieldValue) SetField<T>(item, property, value);
//If field name and type matches, then set.
else if (field.Name == property && field.FieldType == typeof(T)) field.SetValue(obj, value);
}
}
您可以这样称呼它:
Set(obj, "fooBar", "qwerty");
请注意,此 目前仅遍历字段 因为这是您的 类 的设置方式(public 字段,而不是属性)。如果要包含属性,可以将其更改为使用属性,或者组合字段和属性并遍历 both.
再说一次,我并不是说要使用这种方法,但可能会给你一些想法。
你可以使用反射,虽然我不太喜欢反射,但我想这是完成你需要的最简单的方法。
下面的代码不是很漂亮,但希望能给你一个想法。
private static void replaceFoobar(object obj)
{
if (obj == null)
return;
const BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.GetProperty | BindingFlags.Instance;
FieldInfo[] members = obj.GetType().GetFields(bindingFlags);
if (!members.Any())
return;
foreach (var item in members)
{
if (item.Name == "fooBar" || item.Name == "<fooBar>k__BackingField")
{
item.SetValue(obj, "qwerty");
}
else
{
object value = item.GetValue(obj);
if (value != null && value is IEnumerable)
{
foreach (var itemE in ((IEnumerable)value))
replaceFoobar(itemE);
}
else
replaceFoobar(value);
}
}
}
我有一个复杂的 class 层次结构:class B 是 class A 的属性,List(class C) 和 class D 是class B 等的属性 - 很多级别的父子关系。 层次结构中的某些 class 具有字符串属性 "foobar"。有些 classes 没有。 我有一个 class A 的实例。我需要在层次结构中找到所有具有属性 "foobar" 的对象,并将其值更改为 "qwerty"。 在 C# 中是否有一种简单的方法来做到这一点?
public class ClassD
{
public string fooBar;
}
public class ClassC
{ }
public class ClassB
{
public List<ClassC> classCList;
public ClassD classDInstance;
public string fooBar;
}
public class ClassA
{
public ClassB classBInstance;
}
您似乎想更改具有给定名称的属性的值。
这很丑陋,但可能会让您了解如何使用 reflection 完成您想要的事情:
static void Set<T>(dynamic obj, string property, T value) {
//Iterate through the fields on your object. Can change this to properties or do both.
foreach (var field in obj.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance)) {
var fieldValue = field.GetValue(obj);
//If we have a collection, then iterate through its elements.
if (field.FieldType.GetInterface("System.Collections.IEnumerable") != null && !(fieldValue is string) && fieldValue != null)
foreach (var item in fieldValue) SetField<T>(item, property, value);
//If field name and type matches, then set.
else if (field.Name == property && field.FieldType == typeof(T)) field.SetValue(obj, value);
}
}
您可以这样称呼它:
Set(obj, "fooBar", "qwerty");
请注意,此 目前仅遍历字段 因为这是您的 类 的设置方式(public 字段,而不是属性)。如果要包含属性,可以将其更改为使用属性,或者组合字段和属性并遍历 both.
再说一次,我并不是说要使用这种方法,但可能会给你一些想法。
你可以使用反射,虽然我不太喜欢反射,但我想这是完成你需要的最简单的方法。
下面的代码不是很漂亮,但希望能给你一个想法。
private static void replaceFoobar(object obj)
{
if (obj == null)
return;
const BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.GetProperty | BindingFlags.Instance;
FieldInfo[] members = obj.GetType().GetFields(bindingFlags);
if (!members.Any())
return;
foreach (var item in members)
{
if (item.Name == "fooBar" || item.Name == "<fooBar>k__BackingField")
{
item.SetValue(obj, "qwerty");
}
else
{
object value = item.GetValue(obj);
if (value != null && value is IEnumerable)
{
foreach (var itemE in ((IEnumerable)value))
replaceFoobar(itemE);
}
else
replaceFoobar(value);
}
}
}