I am facing a problem about PropertyInfo .My code is here
Type type = typeof(T);
PropertyInfo propertyInfo = type.GetProperty(filterDescriptor.Member);
if (propertyInfo != null && propertyInfo.PropertyType.FullName.ToLower() == "system.string")
{
isMemberStringType = true;
filterDescriptor.Value = filterDescriptor.Value ?? string.Empty;
}
Problem is propertyInfo getting NULL if filterDescriptor.Member contains value like
abc.key
abc.Name
But when it contains Just Key and Name ,It works,it get system.string and execute if .How do i over come this.Help.
MSDN documentation makes it very clear:
Parameters
name
Type: System.String
The string containing the name of the public property to get.
No class can contain property with dot (.) in name.
What you are trying to achieve (I think) is to check child property (e.g. your class has property named abc and class of that property has its own property named key).
To do so, you have to use recursion.
public bool HasPropertyInPath(
Type checkedType,
string propertyPath,
Type propertyType)
{
int dotIndex = propertyPath.IndexOf('.');
if (dotIndex != -1)
{
PropertyInfo topPropertyInfo
= checkedType.GetProperty(propertyPath.Substring(0, dotIndex));
if (topPropertyInfo == null)
{
return false;
}
return HasPropertyInPath(
topPropertyInfo.PropertyType,
propertyPath.Substring(dotIndex + 1),
propertyType);
}
PropertyInfo propertyInfo = checkedType.GetProperty(propertyPath);
return (propertyInfo != null && propertyInfo.PropertyType == propertyType);
}
Then you can use it like this:
if (HasPropertyInPath(typeof(T), filterDescriptor.Member, typeof(string))
{
isMemberStringType = true;
filterDescriptor.Value = filterDescriptor.Value ?? string.Empty;
}
Above code is not tested but should check children properties.
This is not possible with simple call of GetProperty because it works only for the current object level. What you want to do is to traverse nested properties. And you should to remember about treating collections differently (because you want to see their elements properties, not the properties of the collection itself):
static System.Reflection.PropertyInfo GetProperty(Type type, string propertyPath)
{
System.Reflection.PropertyInfo result = null;
string[] pathSteps = propertyPath.Split('.');
Type currentType = type;
for (int i = 0; i < pathSteps.Length; ++i)
{
string currentPathStep = pathSteps[i];
result = currentType.GetProperty(currentPathStep);
if (result.PropertyType.IsArray)
{
currentType = result.PropertyType.GetElementType();
}
else
{
currentType = result.PropertyType;
}
}
return result;
}
and then you can 'query' objects with 'paths':
PropertyInfo pi = GetProperty(c1.GetType(), "ArrayField1.Char");
PropertyInfo pi2 = GetProperty(c2.GetType(), "Color");
See more for reference in this answer.
Hi I have created a List of objects and when I try to acces the properties I get an error saying that the object does not contain a definition for that property.Here is my code:
This is is where I create the List of objects:
public List<object> returnProductData(SetProduct product)
{
List<object> productData = new List<object>();
var type = product.GetType();
var properties = type.GetProperties();
foreach (var propertyInfo in properties)
{
if( propertyInfo.GetValue(product , null) != null && propertyInfo.Name != "ProductName" &&
propertyInfo.Name != "Brand" && propertyInfo.Name != "ProductPrice" && propertyInfo.Name != "ProductImagePath" )
{
productData.Add(new { propertyName = propertyInfo.Name , propertyValue = propertyInfo.GetValue(product , null).ToString()}) ;
}
}
return productData;
}
This is where I try to acces it:
#foreach( var productData in ion)
{
<li>#productData.propertyName</li>
}
When I try to acces it it says that the object does not contain a definition for propertyName.What am I doing wrong here?
You should not return List<object> you should use a more specific type, e.g. List<ProductData>.
If that class doesn't exist then write it.
The object hasn't propertyName property.
If described scenario is very necessary and if you use .net 4.0 or above you can use dynamic like this:
public List<dynamic> returnProductData(SetProduct product)
{
List<dynamic> productData = new List<dynamic>();
var type = product.GetType();
var properties = type.GetProperties();
foreach (var propertyInfo in properties)
{
if( propertyInfo.GetValue(product , null) != null && propertyInfo.Name != "ProductName" &&
propertyInfo.Name != "Brand" && propertyInfo.Name != "ProductPrice" && propertyInfo.Name != "ProductImagePath" )
{
productData.Add(new { propertyName = propertyInfo.Name , propertyValue = propertyInfo.GetValue(product , null).ToString()}) ;
}
}
return productData;
}
Usage:
#foreach( var productData in ion)
{
<li>#productData.propertyName</li>
}
I have multiple large objects which each have about 60 strings. I have to trim all those strings, and I'd like to do so without having to go this.mystring = this.mystring.Trim(). Instead, I'm looking for a way to automatically have each object discover its own strings and then perform the operation.
I know a little bit about reflection, but not enough, but I think this is possible?
Also, I'm not sure if this matters, but some string properties are read-only (only have a getter), so those properties would have to be skipped.
Help?
Well, it's easy enough to get all the properties, and find out which ones are strings and writable. LINQ makes it even easier.
var props = instance.GetType()
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
// Ignore non-string properties
.Where(prop => prop.PropertyType == typeof(string))
// Ignore indexers
.Where(prop => prop.GetIndexParameters().Length == 0)
// Must be both readable and writable
.Where(prop => prop.CanWrite && prop.CanRead);
foreach (PropertyInfo prop in props)
{
string value = (string) prop.GetValue(instance, null);
if (value != null)
{
value = value.Trim();
prop.SetValue(instance, value, null);
}
}
You may want to only set the property if trimming actually makes a difference, to avoid redundant computations for complex properties - or it may not be an issue for you.
There are various ways of improving the performance if necessary - things like:
Simply caching the relevant properties for each type
Using Delegate.CreateDelegate to build delegates for the getters and setters
Possibly using expression trees, although I'm not sure whether they'd help here
I wouldn't take any of those steps unless performance is actually a problem though.
Something like:
foreach (PropertyInfo prop in obj.GetType().GetProperties(
BindingFlags.Instance | BindingFlags.Public))
{
if (prop.CanRead && prop.CanWrite && prop.PropertyType == typeof(string)
&& (prop.GetIndexParameters().Length == 0)) // watch for indexers!
{
var s = (string)prop.GetValue(obj, null);
if (!string.IsNullOrEmpty(s)) s = s.Trim();
prop.SetValue(obj, s, null);
}
}
Not necessary to make IEnumerable check in the props-loop and if actual instance is a IEnumerable, props are ignored. Fix for IEnumerable part:
private void TrimWhitespace(object instance)
{
if (instance != null)
{
if (instance is IEnumerable)
{
foreach (var item in (IEnumerable)instance)
{
TrimWhitespace(item);
}
}
var props = instance.GetType()
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
// Ignore indexers
.Where(prop => prop.GetIndexParameters().Length == 0)
// Must be both readable and writable
.Where(prop => prop.CanWrite && prop.CanRead);
foreach (PropertyInfo prop in props)
{
if (prop.GetValue(instance, null) is string)
{
string value = (string)prop.GetValue(instance, null);
if (value != null)
{
value = value.Trim();
prop.SetValue(instance, value, null);
}
}
else
TrimWhitespace(prop.GetValue(instance, null));
}
}
}
So to expand on this a little, I have a complex object with Lists of Lists and I wanted to traverse that and trim all of the child string objects as well. I'm posting what I did as of what I built on from #Jon did in his answer. I'm curious if there was a better way to do it or if I missed something obvious.
The objects I have are more complex than this but it should illustrate what I was trying.
public class Customer
{
public string Name { get; set; }
public List<Contact> Contacts { get; set; }
}
public class Contact
{
public string Name { get; set; }
public List<Email> EmailAddresses {get; set;}
}
public class Email
{
public string EmailAddress {get; set;}
}
private void TrimWhitespace(object instance)
{
if (instance != null)
{
var props = instance.GetType()
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
// Ignore indexers
.Where(prop => prop.GetIndexParameters().Length == 0)
// Must be both readable and writable
.Where(prop => prop.CanWrite && prop.CanRead);
foreach (PropertyInfo prop in props)
{
if (instance is IEnumerable)
{
foreach (var item in (IEnumerable)instance)
{
TrimWhitespace(item);
}
}
else if (prop.GetValue(instance, null) is string)
{
string value = (string)prop.GetValue(instance, null);
if (value != null)
{
value = value.Trim();
prop.SetValue(instance, value, null);
}
}
else
TrimWhitespace(prop.GetValue(instance, null));
}
}
}
Thoughts?
I have a function with this code:
foreach (PropertyInfo propertyInfo in typeof(T).GetProperties()){
//SOME CODE
if (propertyInfo.CanWrite)
propertyInfo.SetValue(myCopy, propertyInfo.GetValue(obj, null), null);
}
I would avoid to check "collection" properties; to do this now I have insert this control:
if (propertyInfo.PropertyType.Name.Contains("List")
|| propertyInfo.PropertyType.Name.Contains("Enumerable")
|| propertyInfo.PropertyType.Name.Contains("Collection"))
continue;
but, It don't like me!
Which is a better way to do it?
I was thinking you might want to check the interfaces the type of the property implements. (Removed redundant interfaces, as IList inherits ICollection and ICollection inherits IEnumerable.)
static void DoSomething<T>()
{
List<Type> collections = new List<Type>() { typeof(IEnumerable<>), typeof(IEnumerable) };
foreach (PropertyInfo propertyInfo in typeof(T).GetProperties())
{
if (propertyInfo.PropertyType != typeof(string) && propertyInfo.PropertyType.GetInterfaces().Any(i => collections.Any(c => i == c)))
{
continue;
}
Console.WriteLine(propertyInfo.Name);
}
}
I added code to not reject string, as it implements IEnumerable, as well, and I figured you might want to keep those around.
In light of the redundancy of the prior list of collection interfaces, it may be simpler just to write the code like this
static void DoSomething<T>()
{
foreach (PropertyInfo propertyInfo in typeof(T).GetProperties())
{
if (propertyInfo.PropertyType != typeof(string)
&& propertyInfo.PropertyType.GetInterface(typeof(IEnumerable).Name) != null
&& propertyInfo.PropertyType.GetInterface(typeof(IEnumerable<>).Name) != null)
{
continue;
}
Console.WriteLine(propertyInfo.Name);
}
}
I would probably check against IEnumerable.
if ((typeof(string) != propertyInfo.PropertyType)
&& typeof(IEnumerable).IsAssignableFrom(propertyInfo.PropertyType))
{
continue;
}
bool isCollection = typeof(System.Collections.IEnumerable)
.IsAssignableFrom(propertyInfo.PropertyType);
Given the following objects:
public class Customer {
public String Name { get; set; }
public String Address { get; set; }
}
public class Invoice {
public String ID { get; set; }
public DateTime Date { get; set; }
public Customer BillTo { get; set; }
}
I'd like to use reflection to go through the Invoice to get the Name property of a Customer. Here's what I'm after, assuming this code would work:
Invoice inv = GetDesiredInvoice(); // magic method to get an invoice
PropertyInfo info = inv.GetType().GetProperty("BillTo.Address");
Object val = info.GetValue(inv, null);
Of course, this fails since "BillTo.Address" is not a valid property of the Invoice class.
So, I tried writing a method to split the string into pieces on the period, and walk the objects looking for the final value I was interested in. It works okay, but I'm not entirely comfortable with it:
public Object GetPropValue(String name, Object obj) {
foreach (String part in name.Split('.')) {
if (obj == null) { return null; }
Type type = obj.GetType();
PropertyInfo info = type.GetProperty(part);
if (info == null) { return null; }
obj = info.GetValue(obj, null);
}
return obj;
}
Any ideas on how to improve this method, or a better way to solve this problem?
EDIT after posting, I saw a few related posts... There doesn't seem to be an answer that specifically addresses this question, however. Also, I'd still like the feedback on my implementation.
I use following method to get the values from (nested classes) properties like
"Property"
"Address.Street"
"Address.Country.Name"
public static object GetPropertyValue(object src, string propName)
{
if (src == null) throw new ArgumentException("Value cannot be null.", "src");
if (propName == null) throw new ArgumentException("Value cannot be null.", "propName");
if(propName.Contains("."))//complex type nested
{
var temp = propName.Split(new char[] { '.' }, 2);
return GetPropertyValue(GetPropertyValue(src, temp[0]), temp[1]);
}
else
{
var prop = src.GetType().GetProperty(propName);
return prop != null ? prop.GetValue(src, null) : null;
}
}
Here is the Fiddle: https://dotnetfiddle.net/PvKRH0
I know I'm a bit late to the party, and as others said, your implementation is fine
...for simple use cases.
However, I've developed a library that solves exactly that use case, Pather.CSharp.
It is also available as Nuget Package.
Its main class is Resolver with its Resolve method.
You pass it an object and the property path, and it will return the desired value.
Invoice inv = GetDesiredInvoice(); // magic method to get an invoice
var resolver = new Resolver();
object result = resolver.Resolve(inv, "BillTo.Address");
But it can also resolve more complex property paths, including array and dictionary access.
So, for example, if your Customer had multiple addresses
public class Customer {
public String Name { get; set; }
public IEnumerable<String> Addresses { get; set; }
}
you could access the second one using Addresses[1].
Invoice inv = GetDesiredInvoice(); // magic method to get an invoice
var resolver = new Resolver();
object result = resolver.Resolve(inv, "BillTo.Addresses[1]");
I actually think your logic is fine. Personally, I would probably change it around so you pass the object as the first parameter (which is more inline with PropertyInfo.GetValue, so less surprising).
I also would probably call it something more like GetNestedPropertyValue, to make it obvious that it searches down the property stack.
You have to access the ACTUAL object that you need to use reflection on. Here is what I mean:
Instead of this:
Invoice inv = GetDesiredInvoice(); // magic method to get an invoice
PropertyInfo info = inv.GetType().GetProperty("BillTo.Address");
Object val = info.GetValue(inv, null);
Do this (edited based on comment):
Invoice inv = GetDesiredInvoice(); // magic method to get an invoice
PropertyInfo info = inv.GetType().GetProperty("BillTo");
Customer cust = (Customer)info.GetValue(inv, null);
PropertyInfo info2 = cust.GetType().GetProperty("Address");
Object val = info2.GetValue(cust, null);
Look at this post for more information:
Using reflection to set a property of a property of an object
In hopes of not sounding too late to the party, I would like to add my solution:
Definitely use recursion in this situation
public static Object GetPropValue(String name, object obj, Type type)
{
var parts = name.Split('.').ToList();
var currentPart = parts[0];
PropertyInfo info = type.GetProperty(currentPart);
if (info == null) { return null; }
if (name.IndexOf(".") > -1)
{
parts.Remove(currentPart);
return GetPropValue(String.Join(".", parts), info.GetValue(obj, null), info.PropertyType);
} else
{
return info.GetValue(obj, null).ToString();
}
}
You don't explain the source of your "discomfort," but your code basically looks sound to me.
The only thing I'd question is the error handling. You return null if the code tries to traverse through a null reference or if the property name doesn't exist. This hides errors: it's hard to know whether it returned null because there's no BillTo customer, or because you misspelled it "BilTo.Address"... or because there is a BillTo customer, and its Address is null! I'd let the method crash and burn in these cases -- just let the exception escape (or maybe wrap it in a friendlier one).
Here is another implementation that will skip a nested property if it is an enumerator and continue deeper. Properties of type string are not affected by the Enumeration Check.
public static class ReflectionMethods
{
public static bool IsNonStringEnumerable(this PropertyInfo pi)
{
return pi != null && pi.PropertyType.IsNonStringEnumerable();
}
public static bool IsNonStringEnumerable(this object instance)
{
return instance != null && instance.GetType().IsNonStringEnumerable();
}
public static bool IsNonStringEnumerable(this Type type)
{
if (type == null || type == typeof(string))
return false;
return typeof(IEnumerable).IsAssignableFrom(type);
}
public static Object GetPropValue(String name, Object obj)
{
foreach (String part in name.Split('.'))
{
if (obj == null) { return null; }
if (obj.IsNonStringEnumerable())
{
var toEnumerable = (IEnumerable)obj;
var iterator = toEnumerable.GetEnumerator();
if (!iterator.MoveNext())
{
return null;
}
obj = iterator.Current;
}
Type type = obj.GetType();
PropertyInfo info = type.GetProperty(part);
if (info == null) { return null; }
obj = info.GetValue(obj, null);
}
return obj;
}
}
based on this question and on
How to know if a PropertyInfo is a collection
by Berryl
I use this in a MVC project to dynamically Order my data by simply passing the Property to sort by
Example:
result = result.OrderBy((s) =>
{
return ReflectionMethods.GetPropValue("BookingItems.EventId", s);
}).ToList();
where BookingItems is a list of objects.
> Get Nest properties e.g., Developer.Project.Name
private static System.Reflection.PropertyInfo GetProperty(object t, string PropertName)
{
if (t.GetType().GetProperties().Count(p => p.Name == PropertName.Split('.')[0]) == 0)
throw new ArgumentNullException(string.Format("Property {0}, is not exists in object {1}", PropertName, t.ToString()));
if (PropertName.Split('.').Length == 1)
return t.GetType().GetProperty(PropertName);
else
return GetProperty(t.GetType().GetProperty(PropertName.Split('.')[0]).GetValue(t, null), PropertName.Split('.')[1]);
}
if (info == null) { /* throw exception instead*/ }
I would actually throw an exception if they request a property that doesn't exist. The way you have it coded, if I call GetPropValue and it returns null, I don't know if that means the property didn't exist, or the property did exist but it's value was null.
public static string GetObjectPropertyValue(object obj, string propertyName)
{
bool propertyHasDot = propertyName.IndexOf(".") > -1;
string firstPartBeforeDot;
string nextParts = "";
if (!propertyHasDot)
firstPartBeforeDot = propertyName.ToLower();
else
{
firstPartBeforeDot = propertyName.Substring(0, propertyName.IndexOf(".")).ToLower();
nextParts = propertyName.Substring(propertyName.IndexOf(".") + 1);
}
foreach (var property in obj.GetType().GetProperties())
if (property.Name.ToLower() == firstPartBeforeDot)
if (!propertyHasDot)
if (property.GetValue(obj, null) != null)
return property.GetValue(obj, null).ToString();
else
return DefaultValue(property.GetValue(obj, null), propertyName).ToString();
else
return GetObjectPropertyValue(property.GetValue(obj, null), nextParts);
throw new Exception("Property '" + propertyName.ToString() + "' not found in object '" + obj.ToString() + "'");
}
I wanted to share my solution although it may be too late. This solution is primarily to check if the nested property exists. But it can be easily tweaked to return the property value if needed.
private static PropertyInfo _GetPropertyInfo(Type type, string propertyName)
{
//***
//*** Check if the property name is a complex nested type
//***
if (propertyName.Contains("."))
{
//***
//*** Get the first property name of the complex type
//***
var tempPropertyName = propertyName.Split(".", 2);
//***
//*** Check if the property exists in the type
//***
var prop = _GetPropertyInfo(type, tempPropertyName[0]);
if (prop != null)
{
//***
//*** Drill down to check if the nested property exists in the complex type
//***
return _GetPropertyInfo(prop.PropertyType, tempPropertyName[1]);
}
else
{
return null;
}
}
else
{
return type.GetProperty(propertyName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
}
}
I had to refer to few posts to come up with this solution. I think this will work for multiple nested property types.
My internet connection was down when I need to solve the same problem, so I had to 're-invent the wheel':
static object GetPropertyValue(Object fromObject, string propertyName)
{
Type objectType = fromObject.GetType();
PropertyInfo propInfo = objectType.GetProperty(propertyName);
if (propInfo == null && propertyName.Contains('.'))
{
string firstProp = propertyName.Substring(0, propertyName.IndexOf('.'));
propInfo = objectType.GetProperty(firstProp);
if (propInfo == null)//property name is invalid
{
throw new ArgumentException(String.Format("Property {0} is not a valid property of {1}.", firstProp, fromObject.GetType().ToString()));
}
return GetPropertyValue(propInfo.GetValue(fromObject, null), propertyName.Substring(propertyName.IndexOf('.') + 1));
}
else
{
return propInfo.GetValue(fromObject, null);
}
}
Pretty sure this solves the problem for any string you use for property name, regardless of extent of nesting, as long as everything's a property.
Based on the original code from #jheddings, I have created a extension method version with generic type and verifications:
public static T GetPropertyValue<T>(this object sourceObject, string propertyName)
{
if (sourceObject == null) throw new ArgumentNullException(nameof(sourceObject));
if (string.IsNullOrWhiteSpace(propertyName)) throw new ArgumentException(nameof(propertyName));
foreach (string currentPropertyName in propertyName.Split('.'))
{
if (string.IsNullOrWhiteSpace(currentPropertyName)) throw new InvalidOperationException($"Invalid property '{propertyName}'");
PropertyInfo propertyInfo = sourceObject.GetType().GetProperty(currentPropertyName);
if (propertyInfo == null) throw new InvalidOperationException($"Property '{currentPropertyName}' not found");
sourceObject = propertyInfo.GetValue(sourceObject);
}
return sourceObject is T result ? result : default;
}
I wrote a method that received one object type as the argument from the input and returns dictionary<string,string>
public static Dictionary<string, string> GetProperties(Type placeHolderType)
{
var result = new Dictionary<string, string>();
var properties = placeHolderType.GetProperties();
foreach (var propertyInfo in properties)
{
string name = propertyInfo.Name;
string description = GetDescriptionTitle(propertyInfo);
if (IsNonString(propertyInfo.PropertyType))
{
var list = GetProperties(propertyInfo.PropertyType);
foreach (var item in list)
{
result.Add($"{propertyInfo.PropertyType.Name}_{item.Key}", item.Value);
}
}
else
{
result.Add(name, description);
}
}
return result;
}
public static bool IsNonString(Type type)
{
if (type == null || type == typeof(string))
return false;
return typeof(IPlaceHolder).IsAssignableFrom(type);
}
private static string GetDescriptionTitle(MemberInfo memberInfo)
{
if (Attribute.GetCustomAttribute(memberInfo, typeof(DescriptionAttribute)) is DescriptionAttribute descriptionAttribute)
{
return descriptionAttribute.Description;
}
return memberInfo.Name;
}
public static object GetPropertyValue(object src, string propName)
{
if (src == null) throw new ArgumentException("Value cannot be null.", "src");
if (propName == null) throw new ArgumentException("Value cannot be null.", "propName");
var prop = src.GetType().GetProperty(propName);
if (prop != null)
{
return prop.GetValue(src, null);
}
else
{
var props = src.GetType().GetProperties();
foreach (var property in props)
{
var propInfo = src.GetType().GetProperty(property.Name);
if (propInfo != null)
{
var propVal = propInfo.GetValue(src, null);
if (src.GetType().GetProperty(property.Name).PropertyType.IsClass)
{
return GetPropertyValue(propVal, propName);
}
return propVal;
}
}
return null;
}
usage: calling part
var emp = new Employee() { Person = new Person() { FirstName = "Ashwani" } };
var val = GetPropertyValue(emp, "FirstName");
above can search the property value at any level
Try inv.GetType().GetProperty("BillTo+Address");