Finden Sie einen privaten Bereich mit Reflexion?
-
01-07-2019 - |
Frage
In Anbetracht dieser Klasse
class Foo
{
// Want to find _bar with reflection
[SomeAttribute]
private string _bar;
public string BigBar
{
get { return this._bar; }
}
}
Ich möchte das private Element _bar finden, die ich mit einem Attribut markieren. Ist das möglich?
Ich habe dies mit Eigenschaften getan, wo ich für ein Attribut ausgesehen habe, aber nie ein privates Mitglied Feld.
Was sind die Bindung Flaggen, die ich brauche zu setzen, die privaten Felder zu bekommen?
Lösung
Verwenden BindingFlags.NonPublic
und BindingFlags.Instance
Flags
FieldInfo[] fields = myType.GetFields(
BindingFlags.NonPublic |
BindingFlags.Instance);
Andere Tipps
Sie können es genauso wie mit einer Eigenschaft:
FieldInfo fi = typeof(Foo).GetField("_bar", BindingFlags.NonPublic | BindingFlags.Instance);
if (fi.GetCustomAttributes(typeof(SomeAttribute)) != null)
...
Get Privatvariablenwert mit Reflexion:
var _barVariable = typeof(Foo).GetField("_bar", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(objectForFooClass);
Sollwert für die private Variable Reflexion:
typeof(Foo).GetField("_bar", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(objectForFoocClass, "newValue");
Wo objectForFooClass ist eine nicht null-Instanz für den Klassentyp Foo.
Eine Sache, die Sie sich bewusst sein müssen, wenn sie auf private Mitglieder widerspiegelt, ist, dass, wenn Ihre Anwendung ist in mittlerer Vertrauenswürdigkeit (wie zum Beispiel, wenn Sie auf einem Shared-Hosting-Umgebung ausgeführt wird) ausgeführt wird, wird es sie nicht finden -. die BindingFlags.NonPublic Option wird einfach ignoriert werden
typeof(MyType).GetField("fieldName", BindingFlags.NonPublic | BindingFlags.Instance)
Nizza Syntax Mit Erweiterungsmethode
Sie können ein beliebiges privates Feld Zugriff von einem beliebigen Typ mit Code wie folgt:
Foo foo = new Foo();
string c = foo.GetFieldValue<string>("_bar");
Für die Sie benötigen, eine Erweiterungsmethode zu definieren, die die Arbeit für Sie tun:
public static class ReflectionExtensions {
public static T GetFieldValue<T>(this object obj, string name) {
// Set the flags so that private and public fields from instances will be found
var bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
var field = obj.GetType().GetField(name, bindingFlags);
return (T)field?.GetValue(obj);
}
}
Ich benutze diese Methode persönlich
if (typeof(Foo).GetFields(BindingFlags.NonPublic | BindingFlags.Instance).Any(c => c.GetCustomAttributes(typeof(SomeAttribute), false).Any()))
{
// do stuff
}
Ja, aber müssen Sie Ihre Bindung Flags setzen für den privaten Feldern suchen (wenn Ihr für das Mitglied außerhalb der Klasseninstanz suchen).
Die Bindung Flagge müssen Sie ist: System.Reflection.BindingFlags.NonPublic
Hier sind einige Erweiterungsmethoden für einfache get und set private Felder und Eigenschaften (Eigenschaften mit Setter):
Anwendungsbeispiel:
public class Foo { private int Bar = 5; } var targetObject = new Foo(); var barValue = targetObject.GetMemberValue("Bar");//Result is 5 targetObject.SetMemberValue("Bar", 10);//Sets Bar to 10
Code:
/// <summary>
/// Extensions methos for using reflection to get / set member values
/// </summary>
public static class ReflectionExtensions
{
/// <summary>
/// Gets the public or private member using reflection.
/// </summary>
/// <param name="obj">The source target.</param>
/// <param name="memberName">Name of the field or property.</param>
/// <returns>the value of member</returns>
public static object GetMemberValue(this object obj, string memberName)
{
var memInf = GetMemberInfo(obj, memberName);
if (memInf == null)
throw new System.Exception("memberName");
if (memInf is System.Reflection.PropertyInfo)
return memInf.As<System.Reflection.PropertyInfo>().GetValue(obj, null);
if (memInf is System.Reflection.FieldInfo)
return memInf.As<System.Reflection.FieldInfo>().GetValue(obj);
throw new System.Exception();
}
/// <summary>
/// Gets the public or private member using reflection.
/// </summary>
/// <param name="obj">The target object.</param>
/// <param name="memberName">Name of the field or property.</param>
/// <returns>Old Value</returns>
public static object SetMemberValue(this object obj, string memberName, object newValue)
{
var memInf = GetMemberInfo(obj, memberName);
if (memInf == null)
throw new System.Exception("memberName");
var oldValue = obj.GetMemberValue(memberName);
if (memInf is System.Reflection.PropertyInfo)
memInf.As<System.Reflection.PropertyInfo>().SetValue(obj, newValue, null);
else if (memInf is System.Reflection.FieldInfo)
memInf.As<System.Reflection.FieldInfo>().SetValue(obj, newValue);
else
throw new System.Exception();
return oldValue;
}
/// <summary>
/// Gets the member info
/// </summary>
/// <param name="obj">source object</param>
/// <param name="memberName">name of member</param>
/// <returns>instanse of MemberInfo corresponsing to member</returns>
private static System.Reflection.MemberInfo GetMemberInfo(object obj, string memberName)
{
var prps = new System.Collections.Generic.List<System.Reflection.PropertyInfo>();
prps.Add(obj.GetType().GetProperty(memberName,
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.FlattenHierarchy));
prps = System.Linq.Enumerable.ToList(System.Linq.Enumerable.Where( prps,i => !ReferenceEquals(i, null)));
if (prps.Count != 0)
return prps[0];
var flds = new System.Collections.Generic.List<System.Reflection.FieldInfo>();
flds.Add(obj.GetType().GetField(memberName,
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.FlattenHierarchy));
//to add more types of properties
flds = System.Linq.Enumerable.ToList(System.Linq.Enumerable.Where(flds, i => !ReferenceEquals(i, null)));
if (flds.Count != 0)
return flds[0];
return null;
}
[System.Diagnostics.DebuggerHidden]
private static T As<T>(this object obj)
{
return (T)obj;
}
}
Ich kam in diesem, während für diese Suche auf Google, so merke ich, ich einen alten Post bin stoßen. Doch das GetCustomAttributes erfordert zwei params.
typeof(Foo).GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
.Where(x => x.GetCustomAttributes(typeof(SomeAttribute), false).Length > 0);
Der zweite Parameter gibt, ob Sie die Vererbungshierarchie suchen möchten