caching reflected properties and their custom attributes in c# - c#

I'm using a custom attribute to grab a property and then set it's value based on another object's value - I'm using reflection to get the attribute like this:
Class Property:
[MyPropertyName("MyString")]
string myString { get; set; }
Populating code:
public void PopulateMyPropertiesFromObject<T>(MyDataArrays dataArrays, T obj) where T : class, new()
{
Type type = typeof (T);
foreach (PropertyInfo propertyInfo in type.GetProperties())
{
foreach (MyPropertyName propName in PropertyInfo.GetCustomAttributes(true).OfType<MyPropertyName>())
{
//Get the value from the array where MyPropertyName matches array item's name property
object value = GetValue(dataArrays, propName);
//Set the value of propertyInfo for obj to the value of item matched from the array
propertyInfo.SetValue(obj, value, null);
}
}
}
I have a collection of these data arrays and so I'm looping through them instantiating a new object of type T and calling this Populate method to populate the new T for each item in the collection.
What's bugging me is how much I'm looking up the MyPropertyName custom attribute because each call to this method will be passing in the same type for obj. on Average this will happen 25 times and then the object's type will change
Is there any way I can cache the properties with their MyPropertyName attribute?Then I'd just have a list of properties + MyPropertyNames to loop through
Or can I access the attributes in a nicer way than I am?
For context: this is all happening server side of an asp.net website, I've got roughly 200-300 objects, each with around 50 properties using the attribute above for the purposes of the method above

yes you can, you can use a static Dictionary
To do so safely, a lock period is required for accessing the dictionary.
To make it thread safe.
// lock PI over process , reflectin data is collected once over all threads for performance reasons.
private static Object _pilock = new Object();
private static Dictionary<string, PropertyInfo> _propInfoDictionary;
public PropertyInfo GetProperty(string logicalKey) {
// try from dict first
PropertyInfo pi;
// lock access to static for thread safety
lock (_pilock) {
if (_propInfoDictionary.TryGetValue(logicalKey, out pi)){
return pi;
}
pi = new PropertyInfo;
// set pi ...... do whatever it takes to prepare the object before saving in dictionary
_propertyInfoDictionary.Add(logicalKey, pi);
} // end of lock period
return pi;
}

Related

Can I call the "Set" method of a struct property using reflection?

I define a struct:
public struct Settable
{
public string SettableProperty { get; set; }
}
I can set the value of the struct's property in the usual way:
s.SettableProperty = "Abc";
However, when I create a method to attempt to set the property by reflection:
public T CreateWithValue<T>(string propName, string propValue)
{
var retObj = Activator.CreateInstance<T>();
var prop = typeof(T).GetProperty(propName);
var _ = prop.SetMethod.Invoke(retObj, new object[] { propValue});
return retObj;
}
...and call it thus:
var x = CreateWithValue<Settable>("SettableProperty", "Abc");
...I end up with SettableProperty initialized to its default value, null. (No exception is thrown.)
Note that if I define Settable as a class instead of a struct, the value is set as expected.
Is it possible to set struct properties using reflection?
The problem here is that retObj is T, a value-type, but Invoke takes object. This boxes the value, which creates an isolated copy on the heap (inside the box), which you then mutate. Your local copy in retObj isn't impacted in any way here, since it is a completely disconnected copy of the value.
Consider instead:
public T CreateWithValue<T>(string propName, string propValue)
{
object retObj = Activator.CreateInstance<T>();
var prop = typeof(T).GetProperty(propName);
prop.SetMethod.Invoke(retObj, new object[] { typedValue });
return (T)retObj;
}
This creates the box earlier, and unboxes it to get the modified value. It is, however, not very efficient (note: I haven't added any inefficiency; the inefficiency is inherent when using an object API with a value-type). You can remove the allocations if you're happy to get much much dirtier.

How would I get all public properties of object faster than with PropertyInfo.GetValue()?

I have the following generic code that iterates over IEnumerable<T> (assuming all objects are exactly of type T) and for each item it retrieves all properties values and appends them to a StringBuilder:
Type t = typeof(T);
var properties = t.GetProperties();
foreach (var item in list)
{
foreach (var property in properties)
{
object value = property.GetValue(item, null);
// feed to StringBuilder
}
}
and btw the IEnumerable comes from a non-trivial Linq-To-Sql query.
So I profile my code and find that of all my code 37,3% time is spent in System.Data.Linq.SqlClient.ObjectReaderCompiler.ObjectReader.MoveNext() and 31,59% time is spent in RuntimePropertyInfo.GetValue().
This is why I'd be happy to find another way of retrieving all properties - one that is faster than calling PropertyInfo.GetValue().
How could I achieve that (preferable keeping the code generic)?
The strategy is to cache a delegate that is not attached to any instance of a particular object. This is a little trickier than it sounds.
Jon Skeet's article on the topic is good for the general case, however I thought I'd offer a simplified solution for this specific case.
The workhorse is Delegate.CreateDelegate which takes a MethodInfo and returns a delegate that takes the instance as a parameter. The MethodInfo is provided by PropertyInfo.GetGetMethod. The trick is that we want all the delegates to return an object but we can't simply use Func<T, object> as the delegate type. That type is not going to be compatible without a boxing instruction for value types.
To do that we leverage a helper method (below it is called CreateDelegateInternal) which we will invoke by reflection with the correct run-time types. Since we only call this once when loading the delegates, it is not too costly. Then we will wrap the strongly-typed delegate in a less strongly typed lambda which will insert the correct conversion.
public static class ReflectionHelper<T>
{
private static readonly IEnumerable<Func<T, object>> propertyDelegates = CreateDelegates().ToArray();
private static IEnumerable<Func<T, object>> CreateDelegates()
{
var helper = typeof(ReflectionHelper<T>).GetMethod("CreateDelegateInternal", BindingFlags.Static | BindingFlags.NonPublic);
var properties = typeof(T).GetProperties();
foreach(var property in properties)
{
var method = helper.MakeGenericMethod(typeof(T), property.PropertyType);
yield return (Func<T, object>)method.Invoke(null, new object[] { property.GetGetMethod() });
}
}
private static Func<T, object> CreateDelegateInternal<T, TReturn>(MethodInfo m)
{
var f = (Func<T, TReturn>)Delegate.CreateDelegate(typeof(Func<T, TReturn>), m);
return t => (object)f(t);
}
public static IEnumerable<Func<T, object>> Properties
{
get { return propertyDelegates; }
}
}
and your code would look something like:
foreach (var item in list)
{
foreach (var property in ReflectionHelper<T>.Properties)
{
object value = property(item);
// feed to StringBuilder
}
}
Obviously, you may want may add some validation (to check the property's CanRead property) and error handling. Also, you may want to tuple up the PropertyInfo in the output so you could print metadata like names, this is left simple for clarity.

Getting specific properties from an object child

Struggled to come up with a decent way to ask/title this question, but will try and illustrate it as best I can.
I am working with a data structure something like this:
public Foo
{
public Bar Bar {get;set;}
}
public Bar
{
public SubTypeA TypeA {get;set;}
public SubTypeB TypeB {get;set;}
...
}
public SubTypeA
{
public int Status {get;set;}
...
}
Note that I am unable to change the data structure for this.
There are many different types in the Bar class, which all have different properties within them, but common to all of them is the property of Status.
What I need to do, is given an object of type Foo, is record the statuses for every item in the Bar object within it. Not every SubType is going to have a value every time though, some could be null.
I can sort of manage it by using a recursive function like below to loop through all the properties. It isn't ideal though I don't think as the loop could get quite large as there could be a lot of properties on each SubType.
private void GetProperties(Type classType, object instance)
{
foreach (PropertyInfo property in classType.GetProperties())
{
object value = property.GetValue(instance, null);
if (value != null)
{
if (property.Name == "Status")
{
Record(classType, value);
}
GetProperties(property.PropertyType, value);
}
}
}
Is this about the only approach that there is for such a problem?
EDIT: Going by the answer given by Selman22, I have come up with another issue wherein I am trying to create an anonymous object based on the status and name of object.
var z = instance.GetType()
.GetProperties()
.Select(x => new
{
status = x.GetValue(instance).GetType().GetProperty("status").GetValue(x, null),
name = x.Name
})
.ToList();
This is throwing an error of Object does not match target type. when trying to retrieve the value. Is this possible in a 1 liner?
Type class contains GetProperty(string name, BindingFlags method) that you can use to retrieve specific property. Instead of looping through every property use this method.
http://msdn.microsoft.com/en-us/library/system.type.getproperty(v=vs.110).aspx
// Get Type object of MyClass.
Type myType=typeof(MyClass);
// Get the PropertyInfo by passing the property name and specifying the BindingFlags.
PropertyInfo myPropInfo = myType.GetProperty("MyProperty", BindingFlags.Public | BindingFlags.Instance);
You can get all Status properties using LINQ instead of recursion:
var barInstance = typeof(Foo).GetProperty("Bar").GetValue(fooInstance);
var statusProperties = barInstance.GetType()
.GetProperties()
.Select(x => x.GetValue(barInstance).GetType().GetProperty("Status"));

Convert Object to NameValueCollection

I have to convert a generic object(s) into a NameValueCollection. I am attempting to use reflection. While I can get the parent properties, I cannot get the properties of a parent property that is an object.
Class One
public string name{get;set}
Class Two
public string desc{get;set}
public One OneName{get;set;}
public static NameValueCollection GetPropertyName(
string objType, object objectItem)
{
Type type = Type.GetType(objType);
PropertyInfo[] propertyInfos = type.GetProperties();
NameValueCollection propNames = new NameValueCollection();
foreach (PropertyInfo propertyInfo in objectItem.GetType().GetProperties())
{
if (propertyInfo.CanRead)
{
var pName = propertyInfo.Name;
var pValue = propertyInfo.GetValue(objectItem, null);
if (pValue != null)
{
propNames.Add(pName, pValue.ToString());
}
}
}
return propNames;
}
I assume there has to be somesort of recursive call but cannot figure out how to do it. Any help is appreciated.
I will assume that you want resulting NameValueCollection to contain properties from both Class One and Class Two when the input is of type Class Two.
Now that we have that established, what you can do is to examine a type of each property.
If it's one of built-in types (Type.IsPrimitive() can help you determine that), you can add the property to resulting NameValueCollection right away. Otherwise, you need to go over each property of that non-primitive type and repeat the process for it again. As you mention, here is the place for recursion.

Using reflection read properties of an object containing array of another object

How can I read the properties of an object that contains an element of array type using reflection in c#. If I have a method called GetMyProperties and I determine that the object is a custom type then how can I read the properties of an array and the values within. IsCustomType is method to determine if the type is custom type or not.
public void GetMyProperties(object obj)
{
foreach (PropertyInfo pinfo in obj.GetType().GetProperties())
{
if (!Helper.IsCustomType(pinfo.PropertyType))
{
string s = pinfo.GetValue(obj, null).ToString();
propArray.Add(s);
}
else
{
object o = pinfo.GetValue(obj, null);
GetMyProperties(o);
}
}
}
The scenario is, I have an object of ArrayClass and ArrayClass has two properties:
-string Id
-DeptArray[] depts
DeptArray is another class with 2 properties:
-string code
-string value
So, this methods gets an object of ArrayClass. I want to read all the properties to top-to-bottom and store name/value pair in a dictionary/list item. I am able to do it for value, custom, enum type. I got stuck with array of objects. Not sure how to do it.
Try this code:
public static void GetMyProperties(object obj)
{
foreach (PropertyInfo pinfo in obj.GetType().GetProperties())
{
var getMethod = pinfo.GetGetMethod();
if (getMethod.ReturnType.IsArray)
{
var arrayObject = getMethod.Invoke(obj, null);
foreach (object element in (Array) arrayObject)
{
foreach (PropertyInfo arrayObjPinfo in element.GetType().GetProperties())
{
Console.WriteLine(arrayObjPinfo.Name + ":" + arrayObjPinfo.GetGetMethod().Invoke(element, null).ToString());
}
}
}
}
}
I've tested this code and it resolves arrays through reflection correctly.
You'll need to retrieve the property value object and then call GetType() on it. Then you can do something like this:
var type = pinfo.GetGetMethod().Invoke(obj, new object[0]).GetType();
if (type.IsArray)
{
Array a = (Array)obj;
foreach (object arrayVal in a)
{
// reflect on arrayVal now
var elementType = arrayVal.GetType();
}
}
FYI -- I pulled this code from a recursive object formatting method (I would use JSON serialization for it now).

Categories

Resources