Getting custom attributes for properties in class and SetValue - c#

I am just trying to play around with some things. I made a kind of an OR/M type mapper thing and because I am using reflection, performance is slow. How can I speed this up or use a better and more efficient approach?
I have a custom attribute with a named parameter and allow multiple
I then use Reflection to:
Get the properties where they contain the custom attribute decoration
for each property found, get the Custom attributes data
for each custom attribute data, get the named arguments
Then I check the named argument memberinfo name to see if it matches the named parameter in question for the attribute and if it does, it gets the value set for that named parameter and finally reads data from the dataReader for that named parameter value and uses .SetValue to set the value read from the reader to the property.
Here is some code (not complete in any way) and was hoping someone can tell me how to gain that perf improvement.
Running it 10,000 times (before this doing an initial call to JIT excersize etc...) gives me these avg times:
3.79ms
doing it the manual way (i.e hardcoded mapping from DB to DTO): 0.05ms
I know this is like "another OR/M" - but it is not quite like that and it is more for my fun than anything.
private T Populate<T>(IDataReader reader) where T : class, new()
{
T val = new T();
if (reader != null && !reader.IsClosed)
{
var propsWithSQLColumnNameAttributes = typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static).Where(prop => Attribute.IsDefined(prop, typeof(SQLColumnNameAttribute)) && prop.CanWrite && prop.GetSetMethod() != null);
foreach (var currentProperty in propsWithSQLColumnNameAttributes)
{
foreach (var currentAttributeForProperty in currentProperty.GetCustomAttributesData())
{
string currentAttribParamValue = null;
foreach (var currentNamedArgument in currentAttributeForProperty.NamedArguments)
{
if (String.Equals(currentNamedArgument.MemberInfo.Name, SQLColumnNameAttribute.PropertyNames.DataColumnNamePropertyName, StringComparison.OrdinalIgnoreCase))
{
currentAttribParamValue = currentNamedArgument.TypedValue.Value == null ? null : currentNamedArgument.TypedValue.Value.ToString();
if (reader.DoesFieldExist(currentAttribParamValue))
{
var dbRecordValue = reader[currentAttribParamValue] == DBNull.Value ? null : reader[currentAttribParamValue];
currentProperty.SetValue(val, dbRecordValue, null);
}
break;
}
}
}
}
}
return val;
}
Not the best of code but regardless, perf is the issue here and would like to know how to improve it, either by using a different approach of reflection or maybe the ordering and kind of algorithm being used is incorrect
Many thanks - I hope this question makes sense.

Take a look at this page http://www.codeproject.com/Articles/503527/Reflection-optimization-techniques and see if it helps you.
It talks about reflection optimization in many scenarios, and once you wanna learn, this could be a great resource.

Related

Very slow Reflection (trying to write a generic wrapper)

I'm trying to write a generic method to wrap an SDK we're using. The SDK provides "AFElement" objects that represent our data object, and each data AFElement has a collection of "AFAttributes" that map to our data objects' properties.
I've created a generic method which uses reflection to check the object it's called for's properties and get them (if they exist) from the AFElement.Attributes:
private T ConvertAFElementTo<T>(AFElement element, T item) where T : class, new()
{
PropertyInfo[] properties = item.GetType().GetProperties();
foreach (PropertyInfo property in properties)
{
//Get the Attribute object that represents this property
AFAttribute attribrute = element.Attributes[property.Name];
if (attribrute != null)
{
//check if we have the same type
if (property.PropertyType.Equals(attribrute.Type))
{
//set our property value to that of the attribute
var v = attribrute.GetValue().Value;
property.SetValue(item, v);
}
//check if we have an AFElement as an Attribute that will need converting to a data object
else if (attribrute.Type.Equals(typeof(AFElement)))
{
AFElement attributeElement = attribrute.GetValue().Value as AFElement;
Type attributeType = null;
//look up it's data type from the template
TypeConversionDictionary.TryGetValue(attributeElement.Template, out attributeType);
if (attributeType != null)
{
//set it as a .NET object
property.SetValue(item, ConvertAFElementTo(attributeElement, Activator.CreateInstance(attributeType)));
}
}
}
}
return item;
}
The idea is I can throw any of my data objects T at this method and it would populate them, and it works, except it's exceptionally slow.
It takes around 10 seconds to get 63 objects (11 properties each, all simple types like Guid, String and Single), 93% of the time is in this conversion method. I've heard reflection wasn't very efficient, but is is this inefficient?
Is there any other way I could do this, or a way to speed things up? Am I being stupid even trying to do something this generic?
The general rule when you do reflection is not to do any lookup operation etc. at execution time, but only once during an initialization step.
In your example, you could have a class for that method that would do the reflection lookup in the static constructor - ONCE when the class is first accessed. All method calls then will use the already evaluated reflection elements.
Reflection has to do a lot - and you really make it a lot harder by being fully dynamic.
I suggest you do more profiling and find out which methods exactly are slow ;) THen try to do the reflection part a little less often.
You can have an AFAMapper class that gets initialized for every pair of Source and Target ;)

Copy ONLY populated values from one object that are not already populated in another object of the same type

I have a requirement to copy ONLY populated values from one object that are not already populated in another object of the same type.
For example we are passed an object, it is only partially instantiated with data, we read the database to get a fully instantiated version of the object – however this may not have changes by the application committed to the database yet – hence we need to move any values from the database version into the passed in version of the object – without overwriting any values that may already exist in the passed in object (as these are the most up to date values).
The code below suggested by Adam Robinson in another post (see below very useful – thanks!) is a good starting point. However I need to extend this – as I only want to copy over values that are NOT already populated on the target object (i.e. need to check the destProperty is not null). However as an added complication, there are internal complex types declared within the object passed in, this code copies the high level sub groups over without going into the individual properties of the sub groups (i.e. any variables declared with the Root cdt I can try and check for null, but all the fields in sub cdts are simply copied over without going through the individual fields).
Any help would be greatly appreciated.
public static void CopyPropertyValues(object source, object destination)
{
var destProperties = destination.GetType().GetProperties();
foreach (var sourceProperty in source.GetType().GetProperties())
{
foreach (var destProperty in destProperties)
{
if (destProperty.Name == sourceProperty.Name &&
destProperty.PropertyType.IsAssignableFrom(sourceProperty.PropertyType))
{
destProperty.SetValue(destination, sourceProperty.GetValue(
source, new object[] { }), new object[] { });
break;
}
}
}
}
First you need to determine what populated means in your book.
Once you determine that, write you own version of the following IsDefaultValue method.
What I have written will answer with true in the following manner:
if it's a bool then it needs to have the false value
if it's an int then it needs to be 0
if it's any class then needs to be null
etc
So here's my version of the method:
public static bool IsDefaultValue(object #object) {
if (null == #object)
return true;
else if (#object.GetType().IsValueType) {
var isDefault = Activator.CreateInstance(#object.GetType()).Equals(#object);
return isDefault;
} else
return false;
}
Then, presuming that you're interested only in the non indexer properties, that you have no hierarchies and that you will always call this method with objects of the same type,
you could just filter out those properties which are not default in the source but are default in the destination.
Then you could traverse the instance graph recursively for those cases when you have a non-default value in your destination properties.
Please not that what I have written here is just a demonstration of how you might be able to accomplish your task. There are intricate details in your particular scenario which you need to address yourself as they are not obvious from you question.
For instance, I assumed it would be a good idea to add a stop condition for the recursive traversal (the remainingDepth parameter)
public static void CopyPropertyValues(object source, object destination, int remainingDepth = 3) {
// we've reached the farthest point we're allowed to go to
// anything beyond this point won't be affected by this method
if (remainingDepth == 0)
return;
// just a check to make sure the following lines won't backfire
if ((null == source) || (null == destination))
throw new ArgumentNullException();
// we'll need to also check that the 2 objects are of the same type
var type = source.GetType();
if (destination.GetType() != type)
throw new ArgumentException("The two objects should be of the same type");
var properties = type.GetProperties()
// just filter out the properties which are indexers (if any)
// and also those properties which are read or write only
.Where(property => (property.GetIndexParameters().Length == 0) &&
property.CanRead && property.CanWrite);
foreach (var property in properties) {
var sourceValue = property.GetValue(source, null);
var destValue = property.GetValue(destination, null);
if (!IsDefaultValue(sourceValue))
if (IsDefaultValue(destValue))
property.SetValue(destination, sourceValue, null);
else
if (sourceValue.GetType() == destValue.GetType())
CopyPropertyValues(sourceValue, destValue, remainingDepth - 1);
}
}
Please note that property enumeration is needed just once since the objects (as you said it yourself in the comments section) are of the same type.
Also please beware of Reflection when performance is of importance.

Passing properties as parameters to be Got and Set

Well, I need to repeat same code for many properties.
I've seen examples taking Action delegates, but they don't fit quite well here.
I want something like this: (see explanation below)
Dictionary<Property, object> PropertyCorrectValues;
public bool CheckValue(Property P) { return P.Value == PropertyCorrectValues[P]; }
public void DoCorrection(Property P) { P.Value = PropertyCorrectValues[P]; }
.
I want to have a dictionary containing many properties and their respective "correct" values. (I know it's not well declared, but that's the idea). Properties are not necessarely inside my class, some of them are in objects of different assemblies.
A method bool CheckValue(Property). This method must access the actual value of the property and compare to the correct value.
And a method a void DoCorrection(Property). This one sets the property value to the correct value.
Remember I have many of those properties, I wouldn't like to call the methods by hand for each property. I'd rather iterate through the dicionary in a foreach statement.
So, the main question is in the title.
I've tried the by ref, but properties don't accept that.
Am I obligated to use reflection??? Or is there another option (if I need, reflection answer will be accepted as well).
Is there anyway I can make a dictionary with pointers in C#? Or some kind of assignment that changes the value of variable's target instead of changing the target to another value?
Thanks for the help.
You can do this using reflection. Get a list of the properties on the object of interest with typeof(Foo).GetProperties(). Your PropertyCorrectValues property can have type IDictionary<PropertyInfo, object>. Then use the GetValue and SetValue methods on PropertyInfo to perform the desired operations:
public bool CheckProperty(object myObjectToBeChecked, PropertyInfo p)
{
return p.GetValue(myObjectToBeChecked, null).Equals(PropertyCorrectValues[p]);
}
public void DoCorrection(object myObjectToBeCorrected, PropertyInfo p)
{
p.SetValue(myObjectToBeCorrected, PropertyCorrectValues[p]);
}
In addition to Ben's code I'd like to contribute the following code fragment:
Dictionary<string,object> PropertyCorrectValues = new Dictionary<string,object>();
PropertyCorrectValues["UserName"] = "Pete"; // propertyName
PropertyCorrectValues["SomeClass.AccountData"] = "XYZ"; // className.propertyName
public void CheckAndCorrectProperties(object obj) {
if (obj == null) { return; }
// find all properties for given object that need to be checked
var checkableProps = from props
in obj.GetType().GetProperties()
from corr in PropertyCorrectValues
where (corr.Key.Contains(".") == false && props.Name == corr.Key) // propertyName
|| (corr.Key.Contains(".") == true && corr.Key.StartsWith(props.DeclaringType.Name + ".") && corr.Key.EndsWith("." + props.Name)) // className.propertyName
select new { Property = props, Key = corr.Key };
foreach (var pInfo in checkableProps) {
object propValue = pInfo.Property.GetValue(obj, null);
object expectedValue = PropertyCorrectValues[pInfo.Key];
// checking for equal value
if (((propValue == null) && (expectedValue != null)) || (propValue.Equals(expectedValue) == false)) {
// setting value
pInfo.Property.SetValue(obj, expectedValue, null);
}
}
}
When using this "automatic" value correction you might also consider:
You cannot create a PropertyInfo object just by knowing the property name and independently of the declaring class; that's why I chose string for the key.
When using the same property name in different classes then you might need to change the code that is doing the actual assignment because the type between the correct value and the property type might differ.
Using the same property name in different classes will always perform the same check (see point above), so you might need a syntax for property names to restrict it to a specific class (simple dot notation, doesn't work for namespaces or inner classes, but might be extended to do so)
If needed you can replace the "check" and "assign" part with separate method calls, but it might be done inside the code block as stated in my example code.

Efficient way of initializing a generic class' fields and/or properties

I am writing a ConfigParser class, which reads from a config file structured like this:
[Section]
option1 = foo
option2 = 12
option3 = ;
...
The information read is actually stored in a Dictionary<string, string>. What i'd like to achieve is the following:
struct ConfigStruct
{
public string option1;
public int option2;
public char option3 { get; set; }
// Any other _public_ fields or properties
}
ConfigParser Cp = new ConfigParser("path/to/config/file"); // Loads content
ConfigStruct Cs = Cp.CreateInstance<ConfigStruct>("Section");
Console.WriteLine(Cs.option1); // foo
Console.WriteLine(Cs.option2.ToString()); // 12
Console.WriteLine(Cs.option3.ToString()); // ;
The struct (or class, it doesn't matter) ConfigStruct, is application-specific, and the ConfigParser class should know nothing about it. Basically, I want to parse the value from a specific option, and store it into the field/property with the same name. Parsing should be done according to the field/property type.
I've developed a stub method for it:
public T CreateInstance<T>(string Section) where T : new()
{
// Gets options dictionary from loaded data
Dictionary<string, string> Options = this.Data[Section];
T Result = new T();
Type StructType = Result.GetType();
foreach (var Field in StructType.GetFields())
{
if (!Options.ContainsKey(Field.Name))
continue;
Object Value;
if (Field.FieldType == typeof(bool))
Value = Boolean.Parse(Options[Field.Name]);
else if (Field.FieldType == typeof(int))
Value = Int32.Parse(Options[Field.Name]);
else if (Field.FieldType == typeof(double))
Value = Double.Parse(Options[Field.Name]);
else if (Field.FieldType == typeof(string))
Value = Options[Field.Name];
else if (Field.FieldType == typeof(char))
Value = Options[Field.Name][0];
// Add any ifs if needed
else { /* Handle unsupported types */ }
Field.SetValue(Result, Value);
}
foreach (var Property in StructType.GetProperties())
{
// Do the same thing with public properties
}
return Result;
}
Do you think this is the right approach to the problem? Or should I move the responsability of initializing the struct to the application logic instead of the ConfigParser class? I know it's more efficient, but using reflection I write this method only once, and works for every struct.
Should I use reflection to invoke Parse() so that I can avoid all those ifs? Or you'd rather make those conversions type by type, to prevent unexpected behaviour?
Thanks for your time.
Assuming there is a specific reason why you are not using app.config/web.config or other built-in configuration files.
I think this comes down to what the rest of the application is doing, but personally I would do it this way. It allows you to get the return type cleanly and you are not passing an extra stuct down the stack that you don't need to be.
Reflection is a fantastic tool but has some overhead so if the list of types is finite then specifying them manually is more efficient, or alternately only reflecting the unknown types. Also I would change your if blocks to a switch statement, you will gain efficiencies if the IL complier can fully optimise the condition block.
I think there is a simpler solution. You could use a custom section handler to store your settings, custom section handlers are well described here: http://devlicio.us/blogs/derik_whittaker/archive/2006/11/13/app-config-and-custom-configuration-sections.aspx).

Filtering an Objects Properties by Name

I am doing some simple sanity validation on various types. The current test I'm working on is checking to make sure their properties are populated. In this case, populated is defined as not null, having a length greater than zero (if a string), or not equal to 0 (if an integer).
The "tricky" part of this test is that some properties are immune to this check. Right now I use a giant if statement that weeds out properties that don't need to be checked.
//Gets all the properties of the currect feature.
System.Reflection.PropertyInfo[] pi = t.GetProperties();
for(int i = 0; i < pi.Length; i++)
{
if(!pi[i].Name.Equals("PropertyOne")
&& !pi[i].Name.Equals("PropertyTwo")
&& !pi[i].Name.Equals("PropertyThree")
//... repeat a bunch more times
&& !pi[i].Name.IndexOf("ValueOne") != -1
&& !pi[i].Name.IndexOf("ValueTwo") != -1
//... repeat a bunch more times
{
//Perform the validation check.
}
}
When profiling, I noticed the if statement is actually performing worse than the reflection (not that the reflection is blazing fast). Is there a more efficient way to filter the properties of several different types?
I've thought about a massive regular expression but I'm unsure on how to format it, plus it would probably be unreadable given its size. I've also considered storing the values in a List and then using Linq but I'm not sure how to handle the cases that use String.IndexOf() to find if the property contains a certain value.
Thanks in advance.
Make a HashSet "exactNames" with PropertyOne, PropertyTwo etc, and then a List "partialNames" with ValueOne, ValueTwo etc. Then:
var matchingProperties = pi.Where(exactNames.Contains(pi.Name) ||
partialNames.Any(name => pi.Name.Contains(name));
foreach (PropertyInfo property in matchingProperties)
{
// Stuff
}
(Odd indenting just to avoid wrapping.)
Note that you could cache the set of properties to validate on a per-type basis, so you only need to go through this check once per type.
Your idea help speed up my program, thank you. However, you had some syntax issues, plus you were matching items found in the lists and I needed items not in the list. Here is the code I ended up using.
List<System.Reflection.PropertyInfo> pi = type.GetProperties().ToList();
var matchingProperties = pi.Where( prop => !PropertyExclusionSet.Contains( prop.Name )
&& !PropertiesPartialSet.Any( name => prop.Name.Contains( name ) ) );
You might consider decorating your properties with attributes that tell what action needs to be done to them.
public class MyClass {
[CheckMe]
public int PropertyOne { get; set; }
[DontCheckMe]
public int PropertyTwo { get; set; }
}

Categories

Resources