Generic Trim Function C# [duplicate] - c#

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?

Related

C# Loop/Iterate through object to get property values with complex property types

I am trying to find a way to loop through and iterate through an object to get all of it's properties (their name and their value) of an object. I can successfully iterate through the simple properties (such as strings, int, etc.., but when it has a property that contains properties - that is where the problem is...
[ Working for Simple string/int/bool properties ], but I need something that will work with nested / complex property types.
foreach (PropertyInfo spotProperties in spot.GetType().GetProperties())
{
// Simple property type (string, int, etc...) add the property and its value to the node.
var attributeName = spotProperties.Name;
resultElement.Add(new XElement(attributeName, spotProperties.GetValue(spot, null)));
}
Sample code of what I am trying to accomplish, but could not get to work
// Unable to get to work loop through complex property types.
foreach (PropertyInfo spotProperties in spot.GetType().GetProperties())
{
if (--spotProperties is complex type then --)
{
// The item is a complex data type, and needs to have it's properties iterated and added to the node.
foreach (PropertyInfo childSpotProperty in spotProperties.GetValue(spot, null).GetType().GetProperties())
{
var attributeName = ((DisplayNameAttribute)childSpotProperty.GetCustomAttributes(typeof(DisplayNameAttribute), false).FirstOrDefault() as DisplayNameAttribute)?.DisplayName ?? childSpotProperty.Name;
//resultElement.Add(new XElement(attributeName, childSpotProperty.GetValue(childSpotProperty, null)));
}
}
else
{
// Simple property type (string, int, etc...) add the property and its value to the node.
var attributeName = spotProperties.Name;
resultElement.Add(new XElement(attributeName, spotProperties.GetValue(spot, null
}
}
Please let me know if anyone has any idea. Thanks, I appreciate any feed back.
You can refactor this to your liking but it should get the basic job done. It uses some recursion to move through all of the properties in the complex objects. It also handles properties that are Enumerable.
public class PropertyInformation
{
public string Name { get; set; }
public object Value { get; set; }
}
public static List<PropertyInformation> ObjectPropertyInformation(object obj)
{
var propertyInformations = new List<PropertyInformation>();
foreach (var property in obj.GetType().GetProperties())
{
//for value types
if (property.PropertyType.IsPrimitive || property.PropertyType.IsValueType || property.PropertyType == typeof(string))
{
propertyInformations.Add(new PropertyInformation { Name = property.Name, Value = property.GetValue(obj) });
}
//for complex types
else if (property.PropertyType.IsClass && !typeof(IEnumerable).IsAssignableFrom(property.PropertyType))
{
propertyInformations.AddRange(ObjectPropertyInformation(property.GetValue(obj)));
}
//for Enumerables
else
{
var enumerablePropObj1 = property.GetValue(obj) as IEnumerable;
if (enumerablePropObj1 == null) continue;
var objList = enumerablePropObj1.GetEnumerator();
while (objList.MoveNext())
{
objList.MoveNext();
ObjectPropertyInformation(objList.Current);
}
}
}
return propertyInformations;
}
This works but it does have a bug.
The fix is shown below:
//for Enumerables
else
{
var enumerablePropObj1 = property.GetValue(obj) as IEnumerable;
if (enumerablePropObj1 == null) continue;
var objList = enumerablePropObj1.GetEnumerator();
while (objList.MoveNext())
{
== if(objList.Current != null)
== {
== propertyInformations.AddRange(ObjectPropertyInformation(objList.Current));
== }
}

loop through an object and find the not null properties

I have 2 instances of the same objects, o1, and o2. If I am doing things like
if (o1.property1 != null) o1.property1 = o2.property1
for all the properties in the object. What would be the most efficient way to loop through all properties in an Object and do that? I saw people using PropertyInfo to check nulll of the properties but it seems like they could only get through the PropertyInfo collection but not link the operation of the properties.
Thanks.
You can do this with reflection:
public void CopyNonNullProperties(object source, object target)
{
// You could potentially relax this, e.g. making sure that the
// target was a subtype of the source.
if (source.GetType() != target.GetType())
{
throw new ArgumentException("Objects must be of the same type");
}
foreach (var prop in source.GetType()
.GetProperties(BindingFlags.Instance |
BindingFlags.Public)
.Where(p => !p.GetIndexParameters().Any())
.Where(p => p.CanRead && p.CanWrite))
{
var value = prop.GetValue(source, null);
if (value != null)
{
prop.SetValue(target, value, null);
}
}
}
Judging from your example i think your looking for something like this:
static void CopyTo<T>(T from, T to)
{
foreach (PropertyInfo property in typeof(T).GetProperties())
{
if (!property.CanRead || !property.CanWrite || (property.GetIndexParameters().Length > 0))
continue;
object value = property.GetValue(to, null);
if (value != null)
property.SetValue(to, property.GetValue(from, null), null);
}
}
If you are going to use this many times, you could use a compiled expression for better performance:
public static class Mapper<T>
{
static Mapper()
{
var from = Expression.Parameter(typeof(T), "from");
var to = Expression.Parameter(typeof(T), "to");
var setExpressions = typeof(T)
.GetProperties()
.Where(property => property.CanRead && property.CanWrite && !property.GetIndexParameters().Any())
.Select(property =>
{
var getExpression = Expression.Call(from, property.GetGetMethod());
var setExpression = Expression.Call(to, property.GetSetMethod(), getExpression);
var equalExpression = Expression.Equal(Expression.Convert(getExpression, typeof(object)), Expression.Constant(null));
return Expression.IfThen(Expression.Not(equalExpression), setExpression);
});
Map = Expression.Lambda<Action<T, T>>(Expression.Block(setExpressions), from, to).Compile();
}
public static Action<T, T> Map { get; private set; }
}
And use it like this:
Mapper<Entity>.Map(e1, e2);

Ignore collection properties in PropertyInfo

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);

Using reflection in C# to get properties of a nested object

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");

How do I use reflection to get properties explicitly implementing an interface?

More specifically, if I have:
public class TempClass : TempInterface
{
int TempInterface.TempProperty
{
get;
set;
}
int TempInterface.TempProperty2
{
get;
set;
}
public int TempProperty
{
get;
set;
}
}
public interface TempInterface
{
int TempProperty
{
get;
set;
}
int TempProperty2
{
get;
set;
}
}
How do I use reflection to get all the propertyInfos for properties explicitly implementing TempInterface?
Thanks.
I think the class you are looking for is System.Reflection.InterfaceMapping.
Type ifaceType = typeof(TempInterface);
Type tempType = typeof(TempClass);
InterfaceMapping map = tempType.GetInterfaceMap(ifaceType);
for (int i = 0; i < map.InterfaceMethods.Length; i++)
{
MethodInfo ifaceMethod = map.InterfaceMethods[i];
MethodInfo targetMethod = map.TargetMethods[i];
Debug.WriteLine(String.Format("{0} maps to {1}", ifaceMethod, targetMethod));
}
The property getter and setter of an explicitly implemented interface property has an unusual attribute. It's IsFinal property is True, even when it is not a member of a sealed class. Try this code to verify my assertion:
foreach (AssemblyName name in Assembly.GetEntryAssembly().GetReferencedAssemblies()) {
Assembly asm = Assembly.Load(name);
foreach (Type t in asm.GetTypes()) {
if (t.IsAbstract) continue;
foreach (MethodInfo mi in t.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)) {
int dot = mi.Name.LastIndexOf('.');
string s = mi.Name.Substring(dot + 1);
if (!s.StartsWith("get_") && !s.StartsWith("set_")) continue;
if (mi.IsFinal)
Console.WriteLine(mi.Name);
}
}
}
Here's a modified solution based on the implementation given in this blog post:
var explicitProperties =
from prop in typeof(TempClass).GetProperties(
BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly)
let getAccessor = prop.GetGetMethod(true)
where getAccessor.IsFinal && getAccessor.IsPrivate
select prop;
foreach (var p in explicitProperties)
Console.WriteLine(p.Name);
Building on the answer by MrKurt:
var targetMethods =
from iface in typeof(TempClass).GetInterfaces()
from method in typeof(TempClass).GetInterfaceMap(iface).TargetMethods
select method;
var explicitProps =
from prop in typeof(TempClass).GetProperties(BindingFlags.Instance |
BindingFlags.NonPublic)
where targetMethods.Contains(prop.GetGetMethod(true)) ||
targetMethods.Contains(prop.GetSetMethod(true))
select prop;
I had to modify Jacob Carpenter's answer but it works nicely. nobugz's also works but Jacobs is more compact.
var explicitProperties =
from method in typeof(TempClass).GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
where method.IsFinal && method.IsPrivate
select method;
A simple helper class that could help:
public class InterfacesPropertiesMap
{
private readonly Dictionary<Type, PropertyInfo[]> map;
public InterfacesPropertiesMap(Type type)
{
this.Interfaces = type.GetInterfaces();
var properties = type.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);
this.map = new Dictionary<Type, PropertyInfo[]>(this.Interfaces.Length);
foreach (var intr in this.Interfaces)
{
var interfaceMap = type.GetInterfaceMap(intr);
this.map.Add(intr, properties.Where(p => interfaceMap.TargetMethods
.Any(t => t == p.GetGetMethod(true) ||
t == p.GetSetMethod(true)))
.Distinct().ToArray());
}
}
public Type[] Interfaces { get; private set; }
public PropertyInfo[] this[Type interfaceType]
{
get { return this.map[interfaceType]; }
}
}
You'll get properties for each interface, even explicitly implemented.
It's overly complex. You have to reflect over the methods/properties of the Interface type, see if they exist in your class type, and compare them to see if they're the "same" when they do exist.
If something is in the interface but not the type you're testing, it's an explicit implementation. If it's in both, but different between the two, it's an explicit interface.
This seems a bit painful for no apparent reason!
My solution is for the case where you know the name of the property you are looking for and is pretty simple.
I have a class for making reflection a bit easier that I just had to add this case to:
public class PropertyInfoWrapper
{
private readonly object _parent;
private readonly PropertyInfo _property;
public PropertyInfoWrapper(object parent, string propertyToChange)
{
var type = parent.GetType();
var privateProperties= type.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance);
var property = type.GetProperty(propertyToChange) ??
privateProperties.FirstOrDefault(p => UnQualifiedNameFor(p) == propertyName);
if (property == null)
throw new Exception(string.Format("cant find property |{0}|", propertyToChange));
_parent = parent;
_property = property;
}
private static string UnQualifiedNameFor(PropertyInfo p)
{
return p.Name.Split('.').Last();
}
public object Value
{
get { return _property.GetValue(_parent, null); }
set { _property.SetValue(_parent, value, null); }
}
}
You cant just do == on name because explicitly implemented properties have fully qualified names.
GetProperties needs both the search flags to get at private properties.
Jacob's code is missing a filter:
var props = typeof(TempClass).GetInterfaces().Where(i => i.Name=="TempInterface").SelectMany(i => i.GetProperties());
foreach (var prop in props)
Console.WriteLine(prop);

Categories