T.Todua
T.Todua

Reputation: 56507

BindingFlags - get all of them (maximum members)

I tried to get all kind of BindingFlags (in order to get all properties):

BindingFlags ALL_BF =    BindingFlags.CreateInstance | BindingFlags.DeclaredOnly | BindingFlags.ExactBinding |  BindingFlags.FlattenHierarchy |  BindingFlags.GetField |  BindingFlags.GetProperty |  BindingFlags.IgnoreCase |  BindingFlags.IgnoreReturn |  BindingFlags.Instance | BindingFlags.InvokeMethod |  BindingFlags.NonPublic |  BindingFlags.OptionalParamBinding |  BindingFlags.Public |  BindingFlags.PutDispProperty |  BindingFlags.PutRefDispProperty | BindingFlags.SetField |  BindingFlags.SetProperty | BindingFlags.Static | BindingFlags.SuppressChangeType ;

however, this returns empty collection:

obj.GetType().GetProperties( ALL_BF ); 

when I tried:

obj.GetType().GetProperties( BindingFlags.Public );

that returned many members.

1 Can someone explain why first method didnt return result? Which one interferes with other one?

2) Which combination I should use, to get ALL (obtainable) members?

Upvotes: 6

Views: 5943

Answers (4)

Servail Catseye
Servail Catseye

Reputation: 132

You should try this:

//All actual properties:
obj.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
//or
obj.GetType().GetProperties((BindingFlags)60);

 //All binding flags (if really needed):
obj.GetType().GetProperties((BindingFlags)(-1));

As you can see, it's not the same. The reason is that the BindingFlags "filters" result both explicitly and implicitly (inverted if so). That said, if you want maximum members you should pass some basic inclusive "request" BindingFlags like Public and Instance and avoid exclusive "postfilter" BindingFlags like DeclaredOnly (excludes inherited members).

Explanation:

It's binding flags, so you most likely need none of them. I guess you think of:

GetMembers(); //Simple way described in MSDN but just syntactically equivalent

BUT! Unfortunately, parameterless version returns only public members for some reason. Then, assuming you need to pass binding flags anyway (in variable, etc.), you'll probably want:

GetMembers((BindingFlags)0); //but it's like passing BindingFlags.Default

Not so obvious, but 0 means "Nothing" (which is BindingFlags.Default), not zero BindingFlags. Then what? Maybe:

GetMembers((BindingFlags)(-1));

Then you suddenly got all the BindingFlags! But not all the members (probably none at all), because they were bound.

Apparently, BindingFlags works like switchable filters: if not specified, it's vice versa (e.g. corresponding members are discarded from the end result). So finally, you need to pass most generic of them. This will be enough for most purposes:

GetMembers(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
//or
GetMembers((BindingFlags)60); //just a sum of int representations of these flags

Why -1 returns all the flags?


You need to use -1 because its binary representation is ...11111111 (for example -2 is ...11111110 etc.), which means that all of its bits are "true". This is the same like using bitwise OR (Bitwise operations) with every BindingFlags constant. You can see it for yourself by using:

Console.WriteLine(Convert.ToString(-1, 2)); //-1 is the converted value(can be variable); 2 means converting to binary

After this you only need to convert the resulted value to BindingFlags as GetMembers-like methods accept only this type.

Upvotes: 10

kofifus
kofifus

Reputation: 19305

I am not sure what you mean by "maximum members"

I recently needed to get ALL members of a type, that is:

  • fields - public/private/static/inherited
  • properties - public/private/static/inherited which do not have backing fields already included above

Here is a solution for that (we need to recourse up the type hierarchy as GetMembers does not return base private fields):

static IEnumerable<MemberInfo> GetMembers(Type type, bool getStatic=true, bool getPrivate=true, bool getBases=true) {
    var memberList = ImmutableList<MemberInfo>.Empty;
    if (type is null || type == typeof(Object)) return memberList;

    var bindingFlags = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public;
    if (getStatic) bindingFlags |= BindingFlags.Static;
    if (getPrivate) bindingFlags |= BindingFlags.NonPublic;

    memberList = memberList.AddRange(type.GetMembers(bindingFlags));
    if (getBases) memberList = memberList.AddRange(GetMembers(type.BaseType, getStatic, getPrivate, getBases));
    return memberList.Where(memberInfo => memberInfo is PropertyInfo || (memberInfo is FieldInfo && memberInfo.GetCustomAttribute<CompilerGeneratedAttribute>() == null)); // filter out property with backing fields
}

Hope this helps

Upvotes: 2

Nebulosar
Nebulosar

Reputation: 1865

Maybe you should try:

obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)

See this question: How to get the list of properties of a class?

Upvotes: 0

thehennyy
thehennyy

Reputation: 4218

The combination of BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic used in GetProperties(...) should be enough. You may want to add BindingFlags.DeclaredOnly depending on your use-case.

(For fast debugging I use ((BindingFlags)62) to create the mentioned combination.)

Upvotes: 4

Related Questions