I want to know the best way to get the prop info and value using reflection for a nested class by its custom attribute name. With below code I can get the prop info via recursion. But is there a better way or using LINQ. Note that I do not want to hard code the class type as similar to other solution
I also want to get the property value by custom attribute
eg var propValue =?????
public class PlanetRoot
{
public void GetNeighborMoon()
{
Planet planet = new Planet();
Product product = new Product();
Neighbor neighbor = new Neighbor();
neighbor.Moons = 10;
neighbor.RingColor = "Red";
product.Neighbors = new List<Neighbor>();
product.Neighbors.Add(neighbor);
planet.Product = product;
//1. Get the RingColor property info of neighbor with attribute MyDBField(Name = "NeighborRing") . Is there a better way
PropertyInfo propInfo = null;
DoRecursiveGetProperty(planet.GetType(), "NeighborRing", out propInfo );
//2. Get the RingColor property value of neighbor with attribute MyDBField(Name = "NeighborRing")
//var propValue = GetPropertyValue(????);
}
}
private static PropertyInfo DoRecursiveGetProperty(Type type, string attribName, out PropertyInfo propInfo)
{
PropertyInfo[] pi = type.GetProperties();
propInfo= null;
foreach (PropertyInfo p in pi)
{
var dbFieldAttribute = (MyDBFieldAttribute)Attribute.GetCustomAttribute(p, typeof(MyDBFieldAttribute));
if (dbFieldAttribute != null && attribName.ToUpper() == dbFieldAttribute.Name.ToUpper())
{
propInfo= p;
//Console.WriteLine(p.Name + " : " + (dbFieldAttribute != null && dbFieldAttribute.Name != null ? dbFieldAttribute.Name : "****"));
return true;
}
if (p.PropertyType.IsClass && !p.PropertyType.IsValueType && !p.PropertyType.IsPrimitive
&& p.PropertyType.FullName != "System.String")
if (propInfo != null) return true;
else DoRecursiveGetProperty(p.PropertyType, attribName, out propInfo);
}
return false;
}
public class Planet
{
public string PlanetId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public Product Product { get; set; }
[MyDBField(Name="PubDate")]
public string Publishdate { get; set; }
}
public class Product
{
public string ProductId { get; set; }
public List<Neighbor> Neighbors { get; set; }
}
public class Neighbor
{
[MyDBField(Name = "NeighborRing")]
public string RingColor { get; set; }
public int Moons { get; set; }
}
public class MyDBFieldAttribute : System.Attribute
{
public string Name { get; set; }
}
In order to get the value for a nested member that might be in a collection, you need to iterate the collections, and track the current object.
Assuming you don't need the resulting PropInfo
for other reasons, just try to get the value:
private static bool TryRecursiveGetValueWithMyDBFieldName(object startObject, string attribName, out object propValue) {
PropertyInfo[] pi = startObject.GetType().GetProperties();
foreach (PropertyInfo p in pi) {
var dbFieldAttribute = (MyDBFieldAttribute)Attribute.GetCustomAttribute(p, typeof(MyDBFieldAttribute));
if (dbFieldAttribute != null && dbFieldAttribute.Name.Equals(attribName, StringComparison.CurrentCultureIgnoreCase)) {
//Console.WriteLine(p.Name + " : " + (dbFieldAttribute != null && dbFieldAttribute.Name != null ? dbFieldAttribute.Name : "****"));
propValue = p.GetValue(startObject);
return true;
}
if (p.PropertyType.IsClass && !p.PropertyType.IsValueType && !p.PropertyType.IsPrimitive &&
!p.PropertyType.FullName.StartsWith("System.")) {
var tryObject = p.GetValue(startObject);
if (tryObject != null && TryRecursiveGetValueWithMyDBFieldName(tryObject, attribName, out propValue))
return true;
}
if (p.PropertyType.IsClass && p.GetValue(startObject) is IEnumerable ip) {
foreach (var obj in ip) {
if (obj != null && TryRecursiveGetValueWithMyDBFieldName(obj, attribName, out propValue))
return true;
}
}
}
propValue = default;
return false;
}
To use it, call with the initial object:
var foundAttrib = TryRecursiveGetValueWithMyDBFieldName(planet, "NeighborRing", out var propValue);
NOTE: This will return the value of the first object with a matching attribute, as eg every member of the List<Neighbor>
member will have the MyDBField
attribute with the Name
property of NeighborRing
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.