Get Non-Inherited Properties - c#

I'm trying to read all of the properties of a given object, reading in only those that are declared on the object's type, excluding those that are inherited. IE:
class Parent {
public string A { get; set; }
}
class Child : Parent {
public string B { get; set; }
}
And so I want to only get B back. Reading the docs, I assumed below was what I needed, but that actually returned nothing at all.
var names = InstanceOfChild.GetType().GetProperties(BindingFlags.DeclaredOnly).Select(pi => pi.Name).ToList();

Just need a couple other BindingFlags
var names = InstanceOfChild.GetType().GetProperties(
BindingFlags.DeclaredOnly |
BindingFlags.Public |
BindingFlags.Instance).Select(pi => pi.Name).ToList();

Try this:
var names = InstanceOfChild.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly).Select(pi => pi.Name).ToList();
I added the BidningFlags.Instance and BindingFlags.Public to the search parameters which according to the MSDN documentation respectfully:
Specifies that instance members are to
be included in the search.
and
Specifies that public members are to
be included in the search.

Related

Get Properties of baseclass and specific inherited class

I have a base class CrmObject and a few classes that inherit it (Aufgabe, Kontakt, ...). I only have a string-value for the child-class and I want to get both the Properties of CrmObject and the specific child-class in one Statement.
I'd get the properties of the child-class like this:
var propertyInfos = typeof(CrmObject).Assembly.GetType("Aufgabe").GetProperties().Where(p => Attribute.IsDefined(p, typeof(ImportParameter)));
But I'd like to get the Properties of CrmObject, too. Possibly within the same statement.
[UPDATE]
This should be it. I'll test it later. Thank you, guys. :)
var propertyInfos = typeof(CrmObject).Assembly.GetType("DAKCrmImport.Core." +crmType).G‌​etProperties().Where(p => Attribute.IsDefined(p, typeof(ImportParameter)));
Weirdly enough you don't need the bindingflag parameter to flatten the hierarchy. Apparently it's the default value? Well .. whatever. It works :)
Works fine for me.
public class CrmObject
{
[ImportParameter]
public string Name { get; set; }
}
public class Aufgabe : CrmObject
{
[ImportParameter]
public int Id { get; set; }
}
public class ImportParameterAttribute : Attribute
{
}
public class InheritenceProgram
{
public static void Main()
{
var propertyInfos = typeof(CrmObject).Assembly.GetType("Aufgabe").GetProperties().Where(p => Attribute.IsDefined(p, typeof(ImportParameterAttribute)));
var list = propertyInfos.ToList();
}
}
As Mark said, you need to specify BindingFlags.FlattenHierarchy.
But when you specify the BindingFlags, you need to specify exactly what you want. That means that you also have to specify BindingFlags.Instance to get the instance members and BindingFlags.Public to include public members.
So the command would look like this:
var propertyInfos = typeof(CrmObject).Assembly.GetType(crmType).G‌​etProperties(BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.Public).Where(p => Attribute.IsDefined(p, typeof(ImportParameter)));
You can read more about it in this great SO answer and in the documentation of Type.GetProperties.

How to get value of property from object of class at runtime using reflection

I have a class something like below:
Class A : B<C>
{
public A(C entity):base(entity)
{}
}
abstract class B<T>
{
public B(T entity)
{
Entity = entity;
}
public T Entity { get; private set; }
}
Class C: D
{
public string prop2{get;set;}
}
Class D
{
public string prop1{get;set;}
}
Main()
{
A obj = new A(new C());
obj.GetType().GetProperty("prop1", BindingsFlag.Instance|BindingsFlag.FlatteredHierarchy)// is null
}
I have object of class A.
I want to get property value from this object at runtime.
I am trying with
obj.GetType().GetProprty("propertyName",
BindingsFlag.FlattenHierarchy).GetValue(obj, null);
However GetProprty() is returing null as that property is declared either in D or C class.
Can someone please suggest me how to achieve this?
Thanks in advance.
GetType().GetProperty("propertyName", BindingsFlag.FlattenHierarchy)
.GetValue(obj, null);
You are misssing binding flag that specifies wheter get instance or static property:
BindingsFlag.FlattenHierarchy | BindingsFlag.Instance
According to MSDN flag BindingsFlag.Instance or BindingsFlag.Static must be specifed explicity in order to get not null values:
You must specify either BindingFlags.Instance or BindingFlags.Static
in order to get a return.
What's more, public properties are exlcuded by default. So if you property is public you need to specify additional flag:
BindingsFlag.FlattenHierarchy | BindingsFlag.Instance | BindingsFlag.Public
Remarks:
Specify BindingFlags.Public to include public properties in the
search.
If property in base is private, FlattenHierarchy will not enumerate it:
(...) private static members in inherited classes are not included
If this is your case, I am afraid that you have to manually travel through base class and search for that property.
Make also sure, that property name is valid and exists.
EDIT:
After your edit, I see the problem. Your class A is not sub-class of D class (you want to get property from D class). That is why getting property value is not working in such way.
You need to follow the following steps:
// get entity prop value
var entityValue =
(obj.GetType()
.GetProperty("Entity",
BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.Public)
.GetValue(obj));
// get prop value
var prop1Value =
entityValue.GetType()
.GetProperty("prop1",
BindingFlags.FlattenHierarchy |
BindingFlags.Instance |
BindingFlags.Public)
.GetValue(entityValue);
Remember to handle null values etc.

Iterate properties and nested first level properties [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I have the following classes
public class Car
{
public int CarId { get; set;}
public string Description { get; set;}
public Engine Engine { get; set;}
}
public class Engine
{
public int EngineId { get; set;}
public int Description { get; set;}
}
Now i want to iterate all the properties in Car and all the properties in Engine, i dont want to hardcode the property names "Car or Engine"
Example to get all properties of Car, where obj is instance of Car.
var properties = obj.GetType().GetProperties(BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.Public);
But this doesnt iterate the properties of Engine.
FlattenHierarchy does not do what you think it does, and instead follows the inheritance hiearchy for static members.
If you'd like to get sub-properties for objects, you'll need to do that yourself:
static IEnumerable<PropertyInfo> FlattenProperties(Type type)
{
// Assumption #1: you do not want "simple" types enumerated
if (!type.IsClass)
return Enumerable.Empty<PropertyInfo>();
// Assumption #2: you want to ignore "the usual suspects"
if (type.Namespace != null && type.Namespace.StartsWith("System"))
return Enumerable.Empty<PropertyInfo>();
// Assumption #3: your class hierarchy won't destroy recursion
// Assumption #4: you simply want the PropertyInfo
return type.GetProperties(BindingFlags.FlattenHierarchy
| BindingFlags.Instance
| BindingFlags.Public)
.SelectMany(pi => new[] { pi }
.Concat(FlattenProperties(pi.PropertyType)));
}
If this is used in code where you (a) know the depth of the recursion, and (b) have the means to alter the code, I'd suggest creating either a base class, interface, or attribute for these types/properties.
// Replace Assumptions #1 and #2 above with this:
// Assumption #5: given interface ISomething { }
if (!typeof(ISomething).IsAssignableFrom(type))
return Enumerable.Empty<PropertyInfo>();
If you need the "property tree" (i.e. Assumption #4 is incorrect):
static IEnumerable<IEnumerable<PropertyInfo>> FlattenProperties(
Type type,
IEnumerable<PropertyInfo> ancestors = null)
{
// change to Assumptions #1/#2 or #5 to yield break
// ...
ancestors = ancestors ?? Enumerable.Empty<PropertyInfo>();
var properties = type.GetProperties(
BindingFlags.FlattenHierarchy
| BindingFlags.Instance
| BindingFlags.Public);
foreach (var property in properties)
{
// again, Assumption #3: your class hierarchy won't destroy recursion
// Assumption #6: you actually want the initial nested property too
yield return ancestors.Concat(new[] { property });
foreach (var nested in FlattenProperties(
property.PropertyType,
ancestors.Concat(new [] { property })))
{
yield return nested;
}
}
}
Which, in the second case, produces output similar to:
// foreach (var tree in FlattenProperties(typeof(Car)))
// {
// Console.WriteLine("{0}", String.Join(".", tree.Select(pi => pi.Name)));
// }
CarId
Description
Engine
Engine.EngineId
Engine.Description
Try this. You've to repeat the same for all properties of a type to get nested properties.
var properties = obj.GetType().GetProperties(BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.Public);
foreach(var pi in properties)
{
var nestedProperties = pi.PropertyType.GetProperties(BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.Public);
}
You can just iterate through the properties of each property's PropertyType, just as you've done to get the first-level properties.
Here's a quick and dirty example using Linq:
var properties =
from p1 in obj.GetType().GetProperties(BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.Public)
from p2 in p1.PropertyType.GetProperties(BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.Public).DefaultIfEmpty()
select new { OuterProperty = p1, InnerProperty = p2 };
foreach(var prop in properties)
{
Console.WriteLine(prop.OuterProperty.Name + (prop.InnerProperty != null ? "." + prop.InnerProperty.Name : ""));
}
Produces the output:
CarId
Description.Chars
Description.Length
Engine.EngineId
Engine.Description
You might want to only evaluate classes in a given namespace (so you don't end up capturing the Length property of Description, for example):
var properties =
from p1 in obj.GetType().GetProperties(BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.Public)
from p2 in p1.PropertyType.Namespace == "MyNamespace"
? p1.PropertyType.GetProperties(BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.Public).DefaultIfEmpty()
: new PropertyInfo[] { null }
select new { OuterProperty = p1, InnerProperty = p2 };
Produces the output:
CarId
Description
Engine.EngineId
Engine.Description
Or perhaps more elegantly if you define a certain attribute to mark the properties you want to traverse:
[AttributeUsage(AttributeTargets.Property)]
public class TraversableAttribute: Attribute { }
public class Car
{
public int CarId { get; set;}
public string Description { get; set;}
[Traversable]
public Engine Engine { get; set;}
}
...
var properties =
from p1 in obj.GetType().GetProperties(BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.Public)
from p2 in p1.GetCustomAttributes(typeof(TraversableAttribute), true).Length > 0
? p1.PropertyType.GetProperties(BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.Public).DefaultIfEmpty()
: new PropertyInfo[] { null }
select new { OuterProperty = p1, InnerProperty = p2 };
This will produce the same output as the previous example.
If you only need the properties from the original class and its 1st lower hierarchy level, then you could just create the following attribute like so.
public class BrowsableAttribute : Attribute { }
Now simply decorate the classes you want to browse for properties, in your case, that would be the Engine class.
[Browsable]
class Engine
{
public int EngineId { get; set; }
public int Description { get; set; }
}
Now all you need to do is use the following extension method.
public static class TypeExtensions
{
public static void BrowseProperties(this Type type)
{
var h1 = typeof(Car).GetProperties().ToList();
var h2 = h1.Where(x => x.PropertyType.GetCustomAttributes(true).OfType<BrowsableAttribute>().Any());
h2.ToList().ForEach(x => h1.AddRange(x.PropertyType.GetProperties()));
h1.ForEach(x => Console.WriteLine(x.Name));
}
}
Which will produce the desired result. To see this, execute the following lines of code.
class Program
{
static void Main()
{
typeof(Engine).BrowseProperties();
Console.Read();
}
}

C# Reflection code not working;

I have this very simple test because the full version doesn't work either;
public class dfd
{
public string g { get; set; }
}
and then;
Type myType = typeof(dfd);
FieldInfo[] b = myType.GetFields(BindingFlags.Public);
When I look at b there is no field info.
{System.Reflection.FieldInfo[0]}
Any ideas?
You have an automatic public property, which defines a private field. If you ask for the non-public fields, you'll get the backing field of that property.
BTW, you need to ask for both BindingFlags.NonPublic | BindingFlags.Instance, otherwise you won't retrieve that field.

How to get value of inherited property using reflection?

How to get inherited property value using reflection?
I try with BindingFlags but still trigger NullReferenceException
object val = targetObject.GetType().GetProperty("position", BindingFlags.FlattenHierarchy).GetValue(targetObject, null);
position is iherited public property and has a declared value.
EDIT:
class myParent
{
public float[] position;
public myParent()
{
this.position = new float[] { 1, 2, 3 };
}
}
class myChild : myParent
{
public myChild() : base() { }
}
myChild obj = new myChild();
PropertyInfo p = obj.GetType().GetProperty("position", BindingFlags.Instance | BindingFlags.Public);
I tried with several combinations with BindingFlags but p always is null :( ,
If you use the overload with BindingFlags you have to explicitly specify all the flags what you are interested.
Also note that: (from MSDN)
You must specify either BindingFlags.Instance or BindingFlags.Static
in order to get a return.
object val = targetObject.GetType()
.GetProperty("position",
BindingFlags.FlattenHierarchy |
BindingFlags.Instance |
BindingFlags.Public)
.GetValue(targetObject, null);
EDIT:
You have a position field not a property !.
(A good place to start learning the difference: Difference between Property and Field in C# 3.0+ especially this answer)
Change your position to a property:
public float[] position { get; set; }
Or you use the targetObject.GetType().GetField(... method to retrieve the field.
BindingFlags.FlattenHierarchy
works only for static members. Be sure to specify
BindingFlags.Instance | BindingFlags.Public
and you should get inherited properties.

Categories