【问题标题】:C# - find all objects which has attribute with specific name, in complex class hierarchyC# - 在复杂的类层次结构中查找所有具有特定名称属性的对象
【发布时间】:2016-02-18 15:55:16
【问题描述】:

我有一个复杂的类层次结构:B 类是 A 类的属性,List(C 类) 和 D 类是 B 类的属性,等等 - 很多级别的父子关系。 层次结构中的某些类具有字符串属性“foobar”。有些课程没有。 我有一个类 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;
}

【问题讨论】:

  • 您是指[XyzAttribute] 意义上的属性还是别的什么?
  • 类似的东西:public class ClassD { public string FooBar;} public class ClassC { } public class ClassB { public List&lt;ClassC&gt; ClassCList; public ClassD classDInstance; public string FooBar; } public class ClassA { public ClassB ClassBInstance; }
  • 您可以在问题中添加编辑吗?它不能作为评论阅读。
  • 您说您想“在 C# 中执行此操作”,那么您是否正在寻找可以为您重命名字段的代码,而不是使用 Resharper 或 Visual Studio 重构?

标签: c# attributes class-hierarchy


【解决方案1】:

你可以使用反射,虽然我不是这样的忠实粉丝,但我想这是完成你需要的最简单的方法。

下面的代码不是很漂亮,但希望能给你一个想法。

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

【讨论】:

    【解决方案2】:

    您似乎想要更改具有给定名称的属性的值

    这很丑陋,但可能会让你知道如何使用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");
    

    请注意,这目前仅遍历字段,因为这是您的类的设置方式(公共字段,而不是属性)。如果要包含属性,可以将其更改为与属性一起使用,或者组合字段和属性并遍历both

    同样,我并不是说要使用这种方法,但可能会给你一些想法。

    【讨论】:

      猜你喜欢
      • 2013-01-04
      • 1970-01-01
      • 1970-01-01
      • 2010-10-17
      • 1970-01-01
      • 2021-06-25
      • 1970-01-01
      相关资源
      最近更新 更多