it-swarm.com.de

Reflektieren eines privaten Feldes von einer Basisklasse

Hier ist die Struktur:

MyClass: SuperClass2

SuperClass2: SuperClass1

superClass2 befindet sich in Product.Web und SuperClass1 befindet sich in der .NET System.Web-Assembly

Ich versuche, SuperClass1 einen Wert in ein privates Bool-Feld zu zwingen. Aber egal was ich versuche, ich kann die Felder nicht dazu bringen, aus dem Nachdenken zurückzukommen.

Ich verwende den folgenden Code mit verschiedenen BindingFlag-Kombinationen, aber bisher hat nichts funktioniert. SuperClass1 ist eine abstrakte Klasse.

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

Hinweise: Wenn ich GetProperties () verwende, erhalte ich eine schöne große Liste, aber wenn ich Bindungsflags spezifiziere, erhalte ich nichts, obwohl es übereinstimmende Eigenschaften gibt. Was ist das Problem?

Das Feld ist auch nicht als intern markiert

Es ist klar, dass ich GetField (String-Name, BindingFlags) verwende, aber GetFlags () nicht zum Laufen bringen kann.

Update : Ich habe versucht, BindingFlags.Instance wie vorgeschlagen hinzuzufügen, aber es funktioniert nicht (wie erwartet). Ich bekomme 2 Felder zurück, die von der Klasse SuperClass1 geerbt werden. Gibt null zurück, wenn es mit GetField verwendet wird (String-Name, Flags)

Hier ist der Code für die Basisklasse, für die ich das Feld abrufen möchte

public abstract class BaseValidator : Label, IValidator
  {
    private bool propertiesChecked;
...
}
20
Dustin Davis

Sie können manuell in die Vererbungskette aufsteigen, um die Basisfelder abzurufen:

In Anbetracht dieser Klassen:

class SuperClass1
{
    private int myField;
}

class SuperClass2 : SuperClass1
{
}

class MyClass : SuperClass2
{

}

Das sollte funktionieren:

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

Diese SO Antwort enthält eine allgemeinere Lösung: GetType () ruft keine Felder ab. GetFields with BindingFlag.Default

33
BrokenGlass

Ähnlich wie bei der BrokenGlass-Lösung könnten Sie dies tun, um sie etwas allgemeiner zu gestalten:

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

Und dann:

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

Als Dienstprogrammmethode:

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

Und dann:

Mine m = new Mine();

SetField(m, "_baseField", 10);
7
Shibumi

Ich denke, Sie müssen das System.Reflection.BindingFlags.Instance-Flag hinzufügen. Verwenden Sie | um es mit der NonPublic-Flagge zu kombinieren.

BEARBEITEN:

Sieht aus wie BrokenGlass es richtig hat. Ich habe den folgenden Schnelltest geschrieben.

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

Das gesuchte Feld wird korrekt angezeigt. (Test wird von BaseValidator abgeleitet)

3
Nathanael

Verlängerungsmethode:

/// <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;
}
2
Glenn Slayden

Wenn die Hierarchie statisch ist, ist dies am einfachsten:

var field = typeof(SuperClass1).GetField("_privateBaseField",System.Reflection.BindingFlags.NonPublic);
0
devi