【问题标题】:Simplest way to get all MemberInfos that reflect the state of an object?获取反映对象状态的所有 MemberInfos 的最简单方法?
【发布时间】:2013-05-12 05:47:36
【问题描述】:

我需要使用反射获取代表对象的精确状态的所有成员。所以这些成员包括字段 (FieldInfo) 和自动属性 ​​(PropertyInfo)。我可以使用

获得所有FieldInfos
type.GetFields(); //ok some flags needed here

并获得 link 中提到的自动实现的属性:

public static bool MightBeCouldBeMaybeAutoGeneratedInstanceProperty(this PropertyInfo info)
{
    bool mightBe = info.GetGetMethod().HasCompilerGeneratedAttribute();
    if (!mightBe)
        return false;

    bool maybe = info.DeclaringType.GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
                                   .Where(f => f.Name.Contains(info.Name))
                                   .Where(f => f.Name.Contains("BackingField"))
                                   .Where(f => f.HasCompilerGeneratedAttribute())
                                   .Any();

    return maybe;
}

public static bool HasCompilerGeneratedAttribute(this MemberInfo mi)
{
    return mi.GetCustomAttributes(typeof(CompilerGeneratedAttribute), true).Any();
}

正如回答者所说,这确实很脆弱。有没有更标准的方法来实现这一目标?我在想,可能是BindingFlags 左右?

type.GetMembers(BindingFlags....) ?

【问题讨论】:

  • 这是针对特定对象类型还是针对任何对象类型?如果你想获取特定类型的状态,并且你拥有它们的代码,你可以添加你自己的特殊属性 [ObjectState] 来标记这些字段
  • @omerschleifer 适用于任何对象类型。我正在考虑一般处理它,而不是去修改所有这些类。
  • 您需要将自动属性支持字段与常规字段区别对待吗?以我的经验,GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); 会抓住他们。还是我误解了这个问题?
  • @JeremyTodd 不,我不需要区别对待它们,我只需要它们。让我试试你的例子。如果它有效,我会通知你,你可以回答:)
  • @nawfal 不确定您想要“面向公众”的内容,但听起来您正在尝试编写自己的序列化过程以将文件输出到要导入的文本(或类似)文件/从其他应用程序导出。在这种情况下,请搜索Serialization,基于​​二进制、xml 和 json 格式的工作已经完成。

标签: c# reflection automatic-properties fieldinfo


【解决方案1】:

如果“对象的确切状态”只是指它包含的所有实例字段(如果不是,你能澄清一下吗?),那么你应该能够用一个语句来做到这一点——两者之间没有显着区别您显式声明的字段,以及编译器为您添加的自动属性的支持字段。如果你定义一个类:

public class FieldInfoTest
{
  private string testField;

  public string TestProperty { get; set; }
}

...您可以一口气访问它们

FieldInfo[] fields = typeof(FieldInfoTest).GetFields(BindingFlags.Instance |
                                                     BindingFlags.Public | 
                                                     BindingFlags.NonPublic);

foreach (var f in fields)
{
  Console.WriteLine(f.Name);
}

这将产生:

testField
<TestProperty>k__BackingField

【讨论】:

  • Jeremy,为这个想法 +1,可能对我有用。但我很想获得该物业(如PropertyInfo
  • @nawfal 你对自动属性有什么特别的兴趣吗?我的意思是,除了它们是由编译器糖实现的这一事实之外,它们与底层的常规属性几乎相同。
  • 在我的情况下,我需要一个自动属性句柄,因为它们是独立成员(至少来自外部世界),而不是普通属性(将具有支持字段)。例如,如果有一个像这样的Person 类:int age; int Age { get { return age; } } string Name { get; set; },那么是什么决定了对象的特定状态?它必须是字段(因为它们构成属性的基础;在外部公开其他内容)和没有支持字段的自动属性 ​​- 因此,ageName 对我来说。
  • 不过,自动属性确实有支持字段。
  • Jeremy,他们确实如此,这就是我首先使用“外部世界”的原因。我希望你明白我为什么特别需要自动属性。因为,正如你所说,它们在任何意义上都是属性,如果我把它们作为属性本身就好了。
【解决方案2】:

杰里米的回答是我能得到的最好的答案。这是另一种选择(我最初在问题本身中提到过):

public static IEnumerable<MemberInfo> GetStateMembers(this Type t)
{
    return t.GetMembers(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
            .Where(m => m.MemberType == MemberTypes.Field && !((FieldInfo)m).Name.Contains('<')
                     || m.MemberType == MemberTypes.Property && ((PropertyInfo)m).IsAutoProperty());
}

public static bool IsAutoProperty(this PropertyInfo prop)
{
    if (!prop.CanWrite || !prop.CanRead)
        return false;

    return prop.DeclaringType.GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
                             .Any(f => f.Name.Contains("<" + prop.Name + ">"));
}

有关其工作原理的更多说明:https://stackoverflow.com/a/16506710/661933

有点 hackish,但这会提供字段和自动属性(不像 Jeremy 的答案只提供字段信息)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-02-24
    • 1970-01-01
    • 2016-02-16
    • 1970-01-01
    • 2018-04-16
    • 2019-06-06
    • 2015-05-21
    • 2017-02-19
    相关资源
    最近更新 更多