2016-02-18 3 views
1

У меня сложная иерархия классов: класс B является атрибутом класса A, List (класс C) и класса D являются атрибутами класса B и т. Д. - много уровней отношений между родителями и детьми. Некоторые классы в иерархии имеют строковый атрибут «foobar». В некоторых классах нет. У меня есть экземпляр класса A. Мне нужно найти все объекты в иерархии с атрибутом «foobar» и изменить его значение на «qwerty». Есть ли простой способ сделать это на C#?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; 
} 
+0

Вы имеете в виду атрибуты в смысле '[XyzAttribute]' или что-то еще? – stuartd

+0

Нечто подобное: 'общественного класса ClassD {публичная строка FooBar;} общественный класс ClassC {} общественный класс ClassB { общественность Списка ClassCList; public ClassD classDInstance; public string FooBar; } общественный класс ClassA { public ClassB ClassBInstance; } ' –

+0

Можете ли вы добавить редактирование в вопрос? Это не читается как комментарий. – stuartd

ответ

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.

Опять же, я не говорю, чтобы использовать этот подход, но может дать вам некоторые идеи.

2

Вы можете использовать Reflection, хотя я не большой поклонник таких, я бы предположил, что это самый простой способ выполнить то, что вам нужно.

Код ниже не очень красивый, но, надеюсь, даст вам представление.

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