找到一个私人领域的反射?

有了这个课程

class Foo
{
// Want to find _bar with reflection
[SomeAttribute]
private string _bar;


public string BigBar
{
get { return this._bar; }
}
}

我想找到私有项目_bar,我将标记一个属性。这可能吗?

我已经对属性进行了此操作,我在其中查找了属性,但从未查找私有成员字段。

我需要设置哪些绑定标志来获得私有字段?

202994 次浏览

是的,但是你需要设置你的绑定标志来搜索私有字段(如果你在类实例之外寻找成员)。

你需要的绑定标志是:System.Reflection.BindingFlags.NonPublic

typeof(MyType).GetField("fieldName", BindingFlags.NonPublic | BindingFlags.Instance)

你可以像对待属性那样做:

FieldInfo fi = typeof(Foo).GetField("_bar", BindingFlags.NonPublic | BindingFlags.Instance);
if (fi.GetCustomAttributes(typeof(SomeAttribute)) != null)
...

使用BindingFlags.NonPublicBindingFlags.Instance标志

FieldInfo[] fields = myType.GetFields(
BindingFlags.NonPublic |
BindingFlags.Instance);

在反射私有成员时需要注意的一件事是,如果您的应用程序运行在中等信任环境中(例如,当您运行在共享托管环境中时),它将找不到它们——BindingFlags。非公共选择将被忽略。

我在谷歌上搜索这个时遇到了这个,所以我意识到我在撞一个旧帖子。然而GetCustomAttributes需要两个参数。

typeof(Foo).GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
.Where(x => x.GetCustomAttributes(typeof(SomeAttribute), false).Length > 0);

第二个参数指定是否希望搜索继承层次结构

使用Reflection获取私有变量的值:

var _barVariable = typeof(Foo).GetField("_bar", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(objectForFooClass);

使用Reflection为私有变量设置值:

typeof(Foo).GetField("_bar", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(objectForFoocClass, "newValue");

其中objectForFooClass是类类型Foo的非空实例。

我个人就使用这种方法

if (typeof(Foo).GetFields(BindingFlags.NonPublic | BindingFlags.Instance).Any(c => c.GetCustomAttributes(typeof(SomeAttribute), false).Any()))
{
// do stuff
}

下面是一些简单的get和set私有字段和属性(带有setter的属性)的扩展方法:

使用的例子:

    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

代码:

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

带有扩展方法的漂亮语法

你可以使用如下代码访问任意类型的私有字段:

Foo foo = new Foo();
string c = foo.GetFieldValue<string>("_bar");

为此,你需要定义一个扩展方法来为你做这些工作:

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

如果你的. net框架大于4.5。您可以使用GetRuntimeFields方法。

此方法返回在指定类型上定义的所有字段,包括继承的、非公共的、实例的和静态的字段。

https://learn.microsoft.com/en-us/dotnet/api/system.reflection.runtimereflectionextensions.getruntimefields?view=net-6.0

var foo = new Foo();
var fooFields = foo.GetType().GetRuntimeFields()