Using Getproperties() with Bindingflags.Declaredonly in .Net Reflection

Using GetProperties() with BindingFlags.DeclaredOnly in .NET Reflection

If you specify any BindingFlags, then you need to specify explicitly what properties you want to get. For example:

sometype.GetProperties (BindingFlags.DeclaredOnly | 
BindingFlags.Public |
BindingFlags.Instance);

GetProperties for inherited/child class with appropriate BindingFlags does not return expected properties


public readonly Guid Id is a field, not a property. Use the GetField method instead:

typeof(ChildClass).GetField("Id", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);

You can check to see if it is readonly by looking at the IsInitOnly property of the FieldInfo class.

var result = typeof(ChildClass).GetField("Id", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
Assert.IsTrue(result.IsInitOnly);

Get by reflection properties of class ,but not from inherited class

You should add BindingFlags.DeclaredOnly to your flags, i.e:

typeof(Child).GetProperties(System.Reflection.BindingFlags.Public
| System.Reflection.BindingFlags.Instance
| System.Reflection.BindingFlags.DeclaredOnly)

Method GetProperties with BindingFlags.Public doesn't return anything

From the documentation of the GetProperties method:

You must specify either BindingFlags.Instance or
BindingFlags.Static in order to get a
return.

BindingFlags - get all of them (maximum members)

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.

How do I ignore all hidden properties of class being inherited using reflection?

You could use a LINQ query to filter out the hidden properties.

var allProps = typeof(Class2).GetProperties(
BindingFlags.Instance | BindingFlags.Public
);

var thePropsYouWant =
from p in allProps
group p by p.Name into g
select g.OrderByDescending(t => t.DeclaringType == typeof(Class2)).First();

See it running here: https://dotnetfiddle.net/V5sGIs

Reflection GetProperties on different custom classes and collections

I believe you are approaching your problem in the wrong way. Instead of reinventing the wheel by creating a custom MediaTypeFormatter you should just use the correct models for your objects and let the serializer do the rest.

An example would be to use extension methods for your purpose:

public static class JsonExtensions
{
public static object CreateModels<T>(this IEnumerable<T> models, string modelName = null)
{
modelName = modelName ?? typeof(T).Name+"Collection";

return new Dictionary<string, object>()
{
{ modelName, models.Select(m => CreateModel(m)) }
};
}

public static IDictionary<string, object> CreateModel<T>(this T model, string modelName = null)
{
modelName = modelName ?? typeof(T).Name;

return new Dictionary<string, object>()
{
{ modelName, GetProperties(model) }
};
}

private static IDictionary<string, object> GetProperties<T>(T obj)
{
var props = typeof(T).GetProperties();
return props.ToDictionary(p => p.Name, p => (object)new { type = p.PropertyType.ToString(), value = p.GetValue(obj, null).ToString() });
}
}

Assuming you are using Json.NET in your project, this is how they are used:

JsonConvert.SerializeObject(new MyPerson { FirstName = "Bob", DateOfBirth = Convert.ToDateTime("1979-03-01") }.CreateModel());

Outputs (pretty printed):

{
"MyPerson": {
"FirstName": {
"type": "System.String",
"value": "Bob"
},
"DateOfBirth": {
"type": "System.DateTime",
"value": "3\/1\/1979 12:00:00 AM"
}
}
}

While:

JsonConvert.SerializeObject(new List<Foo>() {
new Foo() { Param1 = "aaa", Param2 = "bbb" },
new Foo() { Param1 = "ccc", Param2 = "ddd" }
}.CreateModels());

Outputs:

{
"FooCollection": [
{
"Foo": {
"Param1": {
"type": "System.String",
"value": "aaa"
},
"Param2": {
"type": "System.String",
"value": "bbb"
}
}
},
{
"Foo": {
"Param1": {
"type": "System.String",
"value": "ccc"
},
"Param2": {
"type": "System.String",
"value": "ddd"
}
}
}
]
}

.NET Fiddle Demo HERE

Note

I see in your examples you are using string and not System.String as type name for the properties. Is not easy to use the aliased type names instead of the CLR true names, but if it is really necessary you may look at this answer for a way to obtain that.

Type.GetProperties returning nothing

This code works perfectly fine for me:

namespace MyNameSpace
{
public class MyClass
{
public MyClass(Type optionsClassType)
{
//A PropertyInfo[0] is returned here
var test1 = optionsClassType.GetProperties();
//Even using typeof
var test2 = typeof(MyClassOptions).GetProperties();
//Or BindingFlags
var test3 = typeof(MyClassOptions).GetProperties
(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance);
}
}

public class MyClassOptions
{
public int MyProperty { get; set; }
}
}

Added BindingFlags.Instance in code. For further information, have a look at this post.


Then call this from outside:

var options = new MyClassOptions();
options.MyProperty = 1234;
var t = options.GetType();
var c = new MyNameSpace.MyClass(t);

NOTE: Be careful with assembly linker

If you're building with linker enabled you may need to use the class somewhere, so it will not be ripped off at compile time. Sometimes, only instantiating the class in your code is not enough, the linker may detect that the instance is never used and will remove it anyway.

Reflection on Properties for highest level one

Try using the DeclaredOnly binding flag in your GetProperties call. This should limit the properties returned to the inheritance (class) level specified.



Related Topics



Leave a reply



Submit