Отражение частного поля из базового класса

19

Вот структура:

MyClass: SuperClass2

SuperClass2: SuperClass1

superClass2 находится в Product.Web и SuperClass1 в сборке .NET System.Web

Я пытаюсь заставить значение в поле private bool на SuperClass1. Но не важно, что я пытаюсь, я не могу вернуть поля из отражения.

Я использую следующий код с различными комбинациями BindingFlag, но до сих пор ничего не работало. SuperClass1 является абстрактным классом.

((SuperClass1)this).GetType().GetFields(System.Reflection.BindingFlags.NonPublic);

Примечания: Когда я использую GetProperties (), я получаю хороший большой список, но когда я указываю какие-либо привязки, я ничего не получаю, даже если есть соответствующие свойства. Какая сделка?

Кроме того, поле не отмечено внутренним

Obvisouly Я бы использовал GetField (имя строки, BindingFlags), но я даже не могу заставить GetFlags () работать.

Обновление . Я попытался добавить BindingFlags.Instance, как было предложено, но он не работает (как и ожидалось). Я возвращаю 2 поля, которые поступают из класса SuperClass1, наследуемого. Возвращает null при использовании с GetField (имя строки, флаги)

Вот код для базового класса. Я пытаюсь получить поле для

public abstract class BaseValidator : Label, IValidator
  {
    private bool propertiesChecked;
...
}
    
задан Dustin Davis 05.08.2011 в 21:43
источник
  • Извините за глупый вопрос, но почему вы это делаете? :) –  sll 05.08.2011 в 21:47
  • Большой вопрос. Из-за Product.Web.SuperClass2, я должен сделать это как работу для реализации поддержки функции, которую они должны уже поддерживать, но не. В основном API имеет виртуальный метод, но ВСЕГДА называет базовую реализацию. Поэтому мне нужно изменить значение поля, чтобы он не выполнял определенные проверки, чтобы я мог запустить мой код. –  Dustin Davis 05.08.2011 в 21:50
  • Пожалуйста, не спрашивайте: «Почему вы хотите это сделать?» - это не полезно или конструктивно - для этого есть миллион действительных причин, и все они разные. Очевидно, код пахнет, но догма не собирается помогать 900 тысячам нас, которые будут сбрасываться здесь через Google. –  BrainSlugs83 18.07.2017 в 21:47

5 ответов

30

Вы можете вручную перейти в цепочку наследования, чтобы получить базовые поля:

Учитывая эти классы:

class SuperClass1
{
    private int myField;
}

class SuperClass2 : SuperClass1
{
}

class MyClass : SuperClass2
{

}

Это должно работать:

var myObj = new MyClass();
var myField = typeof(MyClass).BaseType
                             .BaseType
                             .GetField("myField", BindingFlags.Instance | BindingFlags.NonPublic);

В этом ответе SO есть более общее решение: Не получать поля из GetType () .GetFields с BindingFlag.Default

    
ответ дан BrokenGlass 05.08.2011 в 22:02
источник
  • Вот и все. Я не видел BaseType. Теперь давайте надеяться, что это приключение решит мою оригинальную проблему ... –  Dustin Davis 05.08.2011 в 22:19
7

В том же духе для решения BrokenGlass вы можете сделать это, чтобы сделать его более общим:

class Base { private int _baseField; }
class Derived : Base { }
class Mine : Derived { }

И затем:

Type t = typeof(Mine);
FieldInfo fi = null;

while (t != null) 
{
    fi = t.GetField("_baseField", BindingFlags.Instance | BindingFlags.NonPublic);

    if (fi != null) break;

    t = t.BaseType; 
}

if (fi == null)
{
    throw new Exception("Field '_baseField' not found in type hierarchy.");
}

Как полезный метод:

public static void SetField(object target, string fieldName, object value)
{
    if (target == null)
    {
        throw new ArgumentNullException("target", "The assignment target cannot be null.");
    }

    if (string.IsNullOrEmpty(fieldName))
    {
        throw new ArgumentException("fieldName", "The field name cannot be null or empty.");
    }

    Type t = target.GetType();
    FieldInfo fi = null;

    while (t != null)
    {
        fi = t.GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic);

        if (fi != null) break;

        t = t.BaseType; 
    }

    if (fi == null)
    {
        throw new Exception(string.Format("Field '{0}' not found in type hierarchy.", fieldName));
    }

    fi.SetValue(target, value);
}

И затем:

Mine m = new Mine();

SetField(m, "_baseField", 10);
    
ответ дан Shibumi 05.08.2011 в 22:12
источник
3

Я думаю, вам нужно добавить флаг System.Reflection.BindingFlags.Instance. Использование | объединить его с флагом NonPublic.

EDIT:

Похоже, что у BrokenGlass все правильно. Я написал следующий быстрый тест.

var fields = test.GetType().BaseType.GetFields(BindingFlags.Instance | BindingFlags.NonPublic);
foreach (var field in fields)
{
     System.Console.WriteLine(field.Name);
}

Он правильно сообщает о поле, которое вы искали. (Тест получен из BaseValidator)

    
ответ дан Nathanael 05.08.2011 в 21:46
источник
  • Я уже пробовал это. –  Dustin Davis 05.08.2011 в 21:47
  • У вас должно быть разрешение, чтобы отражать частные поля. Не могли бы вы предоставить поле, к которому вы пытаетесь получить доступ, и класс, из которого вы работаете в System.Web? (Для этого вам обязательно понадобится флаг экземпляра.) –  Nathanael 05.08.2011 в 21:52
  • «System.Web.UI.WebControls.BaseValidator», и я хочу установить propertiesChecked –  Dustin Davis 05.08.2011 в 21:57
1

Метод расширения:

/// <summary>
/// Returns the FieldInfo matching 'name' from either type 't' itself or its most-derived 
/// base type (unlike 'System.Type.GetField'). Returns null if no match is found.
/// </summary>
public static FieldInfo GetPrivateField(this Type t, String name)
{
    const BindingFlags bf = BindingFlags.Instance | 
                            BindingFlags.NonPublic | 
                            BindingFlags.DeclaredOnly;

    FieldInfo fi;
    while ((fi = t.GetField(name, bf)) == null && (t = t.BaseType) != null)
        ;
    return fi;
}
    
ответ дан Glenn Slayden 31.01.2018 в 22:27
источник
0

Если иерархия статична, это самый простой способ:

var field = typeof(SuperClass1).GetField("_privateBaseField",System.Reflection.BindingFlags.NonPublic);
    
ответ дан devi 06.09.2016 в 12:56
источник