Bu sınıfa verilen
class Foo
{
// Want to find _bar with reflection
[SomeAttribute]
private string _bar;
public string BigBar
{
get { return this._bar; }
}
}
Bir öznitelikle işaretleyeceğim özel öğeyi _bar bulmak istiyorum. Mümkün mü?
Bunu bir özellik aradığım özelliklerle yaptım ancak hiçbir zaman özel üye alanı olmadı.
Özel alanları elde etmek için ayarlamam gereken bağlayıcı bayraklar nelerdir?
BindingFlags.NonPublic
ve BindingFlags.Instance
bayraklarını kullanın
FieldInfo[] fields = myType.GetFields(
BindingFlags.NonPublic |
BindingFlags.Instance);
Aynen bir özellik gibi yapabilirsiniz:
FieldInfo fi = typeof(Foo).GetField("_bar", BindingFlags.NonPublic | BindingFlags.Instance);
if (fi.GetCustomAttributes(typeof(SomeAttribute)) != null)
...
Reflection kullanarak özel değişkenin değerini al:
var _barVariable = typeof(Foo).GetField("_bar", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(objectForFooClass);
Reflection kullanarak özel değişken için değer ayarlayın:
typeof(Foo).GetField("_bar", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(objectForFoocClass, "newValue");
ObjectForFooClass, Foo sınıfı için boş olmayan bir örnek olduğunda.
Özel üyelere yansırken dikkat etmeniz gereken bir şey, uygulamanızın orta düzeyde güven içinde (örneğin, paylaşılan bir barındırma ortamında çalışırken), onları bulmayacak olmasıdır. BindingFlags.NonPublic seçeneği sadece göz ardı edilir.
typeof(MyType).GetField("fieldName", BindingFlags.NonPublic | BindingFlags.Instance)
İsteğe bağlı türdeki herhangi bir özel alana aşağıdaki kodla erişebilirsiniz:
Foo foo = new Foo();
string c = foo.GetFieldValue<string>("_bar");
Bunun için işi sizin için yapacak bir uzatma yöntemi tanımlamanız gerekir:
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);
}
}
Bu yöntemi şahsen kullanırım
if (typeof(Foo).GetFields(BindingFlags.NonPublic | BindingFlags.Instance).Any(c => c.GetCustomAttributes(typeof(SomeAttribute), false).Any()))
{
// do stuff
}
Basit alma ve ayarlama özel alanlar ve özellikleri için bazı uzatma yöntemleri:
kullanım örneği:
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
Kod:
/// <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;
}
}
Evet, ancak ciltleme bayraklarınızı özel alanlar aramaya ayarlamanız gerekir (eğer sınıf örneğinin dışındaki üyeyi arıyorsanız).
İhtiyacınız olacak bağlayıcı bayrak: System.Reflection.BindingFlags.NonPublic
Bunu Google’da arama yaparken karşılaştım, bu yüzden eski bir yazıya çarptığımı fark ediyorum. Ancak GetCustomAttributes iki param gerektirir.
typeof(Foo).GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
.Where(x => x.GetCustomAttributes(typeof(SomeAttribute), false).Length > 0);
İkinci parametre, miras hiyerarşisini aramak isteyip istemediğinizi belirtir