Cache Reflection Results (Class Properties) - c#

considering that fairly static data should not be re-evaluated but cached instead, I wondered if it is possible to use Reflection to obtain class properties once, and then cache them so that I could dynamically evaluate object properties and read/assign values, but not have the Reflection overhead every time I do that. Is this possible (Sample code?) ?
To clarify a bit, lets say I have this class:
public class Cloud
{
Boolean IsWhite;
}
and I'm trying to now make a method that allows me to do something like this (pseudocode):
Update(myCloudInstance, new {IsWhite, true});
Update should now check with the cache first if it knows already the properties of Cloud (typeof(myCloudInstance)), and then use cached information to assign the property "IsWhite" the value "true" instead of doing Reflection again.
Any ideas on how to do this?

It's not clear exactly what you're doing, but caching can certainly make a difference with reflection.
In particular, if you're invoking methods (or property getters/setters) and can do so in a type-safe way as far as the calling code is concerned, it can make a huge difference if you convert the MethodInfo into a strongly-typed delegate once and then reuse that.
If you could give us a complete example of what you're trying to do, that would help us to come up with more specific ideas or even code. If you're just going to cache a PropertyInfo that may not have as much (or any) effect - it's possible that the normal Type.GetProperty (etc) methods are already pretty fast. As ever with performance questions, the key is to measure what you're actually doing. Make a change and measure again, etc.

The cost of reflection does not need to be as big as you think. In addition to delegates (that Jon discusses) you can also use things like HyperDescriptor to minimise the cost of reflection without changing the code much - it simply becomes PropertyDescriptor instead:
PropertyDescriptorCollection props = TypeDescriptor.GetProperties(myCloudInstance);
// ideally cache props, but not essential
then
object val = props["IsWhite"].GetValue(myCloudInstance);
or if you use it lots, consider storing the PropertyDescriptor somewhere, too.
However... like Jon, I'm really not 100% sure what you're trying to do!

I created a hashtable to cache the reflection results. First time, it's neccessary to make a call to GetProperties and store the results into the hastable. Next times, first check the hashtable for the List of PropertyInfo objects. If exists, use it. If not, invoke GetProperties.
I use this to map a datareader to a List of Entities.
My implementation is based on: A Defense on Reflection in .Net, by Nick Harrison (http://www.simple-talk.com/dotnet/.net-framework/a-defense-of-reflection-in-.net/).
So, there it is:
public class MapeadorDataReaderListaObjetos
{
private Hashtable properties;
private Hashtable Properties
{
get
{
if (properties == null)
properties = new Hashtable();
return properties;
}
set { properties = value; }
}
private void LoadProperties(object targetObject, Type targetType)
{
var flags = BindingFlags.DeclaredOnly| BindingFlags.Instance| BindingFlags.Public;
if (properties == null)
{
List<PropertyInfo> propertyList = new List<PropertyInfo>();
PropertyInfo[] objectProperties = targetType.GetProperties(flags);
foreach (PropertyInfo currentProperty in objectProperties)
{
propertyList.Add(currentProperty);
}
properties = new Hashtable();
properties[targetType.FullName] = propertyList;
}
if (properties[targetType.FullName] == null)
{
List<PropertyInfo> propertyList = new List<PropertyInfo>();
PropertyInfo[] objectProperties = targetType.GetProperties(flags);
foreach (PropertyInfo currentProperty in objectProperties)
{
propertyList.Add(currentProperty);
}
properties[targetType.FullName] = propertyList;
}
}
public void MapearDataReaderListaObjetos <T> (IDataReader dr, List<T> lista) where T: new()
{
Type businessEntityType = typeof(T);
List<T> entitys = new List<T>();
T miObjeto = new T();
LoadProperties(miObjeto, businessEntityType);
List<PropertyInfo> sourcePoperties = Properties[businessEntityType.FullName] as List<PropertyInfo>;
while (dr.Read())
{
T newObject = new T();
for (int index = 0; index < dr.FieldCount; index++)
{
for (int _indice = 0; _indice < sourcePoperties.Count; _indice++)
{
if (sourcePoperties[_indice].Name.ToUpper() == dr.GetName(index).ToUpper());
{
string _tipoProp = sourcePoperties[_indice].PropertyType.ToString();
PropertyInfo info = sourcePoperties[_indice] as PropertyInfo;
if ((info != null) && info.CanWrite)
{
info.SetValue(newObject, dr.GetValue(index), null);
}
}
}
}
entitys.Add(newObject);
}
dr.Close();
lista = entitys;
}
}
Then, I call it from my DataAcces Layer, like this:
public List <Entities.ENFactura> ListaxIdFactura (SqlTransaction Tr, Entities.ENFactura oBEFactura)
{
SqlConnection Cn = new SqlConnection();
Cn = _Connection.ConexionSEG();
List<Entities.ENFactura> loBEFactura = new List<Entities.ENFactura>();
using (Cn)
{
Cn.Open();
SqlDataReader drd = (odaSQL.fSelDrd(Cn, Tr, "Pa_CC_Factura_Listar_x_IdProveedor", oBEFactura));
if (drd != null)
{
if (drd.HasRows)
{
mapeador.MapearDataReaderListaObjetos <ENFactura>(drd, loBEFactura);
}
}
}
return (loBEFactura);
}
So, this way, the DAL gets a datareader, map it to a list of business entities, and return it to the Business Logic Layer.
This class (MapeadorDataReaderListaObjetos) has some issues still, particularly at:
info.SetValue(newObject, _valor, null);
newObject and _valor must be the same type or you'll get an exception (conversion from System.Int64 to System.Int32, in case your entity property is Int32 and its corresponding field at the database table is bigint, for example).
Also, if an entity property is another entity, this will not work, because datareaders do not return entity objects.
Obviously, this can be improved.
Regarding reflection and delegates, i found this article: Reflection - Slow or Fast? Demonstration with Solutions, by Abhishek Sur, at
http://www.abhisheksur.com/2010/11/reflection-slow-or-faster-demonstration.html
Another good article is: Dodge Common Performance Pitfalls to Craft Speedy Applications, by Joel Pobar, at http://msdn.microsoft.com/en-us/magazine/cc163759.aspx.
Hope this helps.

I think the best way to do it is to get the getter or setter method, convert it to a delegate, and work with the delegate, there is no faster way:
PropertyInfo propertyInfoProperty1 = type.GetType().GetProperty("Property1");
Func<TYPE, string> get_Property1 = (Func<TYPE, string>)Delegate.CreateDelegate(typeof(Func<TYPE, string>), propertyInfoProperty1.GetGetMethod());
Then call the getter method:
string value = get_Property1(type);
You can cache the delegates.

Dynamic assembly should help with the concern about reflection performance. Somebody has implemented property assessors using dynamic assembly here.

Related

Reflection Setting values of a class

I am trying to build an extension to populate an object with values from a SQLDataReader.
The code I have so far is
public static T RetunObject<T>(this Type source, SqlDataReader dr)
{
Type type = source.GetType();
PropertyInfo[] properties = type.GetProperties();
foreach (PropertyInfo property in properties)
{
property.SetValue(property, dr[property.Name]);
type.GetProperty(property.Name).SetValue(type, dr[property.Name]);
}
return type.Cast<T>();
}
One thing for sure is the last line is not right and not exactly sure if there is a way for this to work at this point.
The goal results would be to use the code like
MyClass myclass = new MyClass();
var results = myclass.ReturnObject(myDataReader);
Reflection has never been my strong suit. so I am pretty sure I am pretty far off.
UPDATED CODE WHICH APPEARS TO WORK
public static object RetunObject(this object source, SqlDataReader dr)
{
while (dr.Read())
{
foreach (PropertyInfo property in source.GetType().GetRuntimeProperties())
{
if(dr.GetSchemaTable().Select("ColumnName='"+ property.Name+"'").Count() == 1)
{
var readervalue = dr.GetValue(dr.GetOrdinal(property.Name));
property.SetValue(source, readervalue);
}
}
}
return source;
}
it is used like
return (Role)role.RetunObject(sqlcomm.ExecuteReader());
Takes a SQLDataReader and returns an generic object which is able to be cast to the object type you need it to be. Obviously if you try to cast to an invalid type of object then it won't work but so far this seems to work. My next trial will be to test nested class to see if it will work there as well.
In your example there is plenty errors and it is completely unclear what you try to accomplish. Probably you tried to just apply properties from reader to your object:
public static T RetunObject<T>(this T source, SqlDataReader dr)
{
var type = typeof(T);
var properties = type.GetProperties();
foreach (var property in properties)
{
property.SetValue(source, dr[property.Name]);
}
return source;
}
But, I recommend you to use Entity Framework for this, because you probably creating another bicycle by doing this. This task was completed a lot better/faster/safer than the solution you try to accomplish.
Try to spend a little of your time on things people commonly use before trying to implement something, that no one beside you will understand/support.
It will be a lot more useful and faster than spending time on potentially buggy code. Here is good start in EF Code First: https://msdn.microsoft.com/en-us/library/jj193542(v=vs.113).aspx

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

Get and save enum using reflection

I have a project in which I have some assemblies which implement an abstract class.
Each assembly has a public enum called ResultEnum.
This ResultEnum's value is stored in a database as an int.
I have another web project which displays some info, and I want it to also display this int's string representation - the name of the corresponding value from the ResultEnum.
What I want to do is, using MEF, load all the relevant assemblies (no problem here), search for this enum using reflection (no problem here also) and then to store the enum in some way, and cache it in order to avoid all this process the next time I want to convert the int from the database to the string representation (and the other way around if necessary) since I have several thousands of records in my db table.
AggregateCatalog catalog = new AggregateCatalog();
catalog.Catalogs.Add(new DirectoryCatalog(path));
_container = new CompositionContainer(catalog);
try
{
_container.ComposeParts(this);
}
catch (CompositionException compositionException)
{
Console.WriteLine(compositionException.ToString());
}
foreach (var task in myTasks)
{
TaskAbstract instance = (TaskAbstract)task.CreateExport().Value;
MemberInfo[] infos = instance.GetType().GetMembers(BindingFlags.Public | BindingFlags.Static);
foreach (MemberInfo member in infos.Where(x => x.Name.Equals("ResultEnum")))
{
Console.WriteLine(member);
}
}
What do you suggest the next move should be?
How should I store/cache it?
Thanks
In addition to #Thomas's answer:
As using reflection you can get exact int value from a property, the name for that concrete value could be gotten using the next expression:
var enumValueName = Enum.GetName(member.GetType(), member.GetValue(instance));
UPD
I really missed that you reflect MemberInfos. To apply my solution you can update you reflection this way:
foreach (var task in myTasks)
{
TaskAbstract instance = (TaskAbstract)task.CreateExport().Value;
// Reflect properties, not all members
PropertyInfo[] infos = instance.GetType().GetProperties(BindingFlags.Public | BindingFlags.Static);
foreach (PropertyInfo prop in infos.Where(x => x.Name.Equals("ResultEnum")))
{
var enumValueName = Enum.GetName(prop.GetType(), prop.GetValue(instance));
}
}
Or you could cast MemberInfo to PropertyInfo.
One approach to solving this problem is to consider using a subclassable enums technique (also sometimes referred to as a polymorphic enum).
I wrote a couple of generic classes specifically to support these kinds of types which you can read about here. Also, a proposal has been submitted to the Roslyn compiler team on Github to add support for these types of enums to C#.
Here is an example of a set of subclassable enums that have two underlying types, string and integer, using the classes from my project:
public sealed class Status : StringIntegerEnum<Status>
{
public static readonly Status Active = new Status("active", 1);
public static readonly Status Inactive = new Status("inactive", 0);
private Status(string status, int statusCode) : base(status, statusCode) {}
}
Note that the string value is not the same as the constant name itself, which allows you to have underlying string values with characters that violate the normal naming conventions in C#.
The StringIntegerEnum<tStringIntegerEnum> base class provides .AllValues, .AllNaturalValues and .AllStringValues static methods that you can use to enumerate the list of enum values or both types of their underlying values.
From your comment:
I agree, But question is how do I iterate over the values and names of the enumerator
I assume you mean "enumeration", not "enumerator". You can use the Enum.GetValues method:
var valuesToNames =
Enum.GetValues(enumType)
.Cast<object>()
.ToDictionary(o => (int)o, o => Enum.GetName(enumType, o));
And, is there a better solution than a dictionary
Better how? I think a dictionary is a fine solution; is there any reason why you would want something else?
This is how i've written the code eventually:
resultEnumsForTasks = new Dictionary<string, Dictionary<UInt16, string>>();
foreach (var task in myTasks)
{
Dictionary<UInt16, string> _enum = new Dictionary<UInt16,string>();
TaskAbstract instance = (TaskAbstract)task.CreateExport().Value;
MemberInfo resultEnum = instance.GetType().GetMember("ResultEnum").FirstOrDefault();
if (resultEnum == null)
continue;
string[] names = Enum.GetNames(resultEnum as Type);
IList<int> vals = (IList<int>)Enum.GetValues(resultEnum as Type);
for (int i = 0; i < names.Length; i++)
{
_enum.Add(Convert.ToUInt16(vals[i]), names[i]);
}
resultEnumsForTasks.Add(instance.GetType().Name, _enum);
}
It's very similar to #n.turakulov 's solution, however his solution didn't work for me since I got an empty list of PropertyInfo for some reason...
Thanks for everyone who assisted!

C#, instantiating a generic type - with variable type argument?

Code example:
void Foo(params object[] objects)
{
var entries = new List<IEntry>();
foreach(var o in objects)
{
var entry = new Entry<o.GetType()>(); // this doesn't work
entries.Add(entry);
}
...
}
Foo("hello", 5); // should fill entries with Entry<string> and Entry<int>
Why is that not possible? I guess I need to work with reflection instead? How to do that properly AND performant?
You just can't use C# generics the way you're trying to do in your snippet.
In order to use [C#] generics, the actual object type must be known at compile time.
You're trying to dynamically pass the object type as a type parameter. This is simply not possible.
Edit
Yes, it is possible to dynamically create generic objects using reflection. After all, generics is implemented both as a compile-time C# construct and as a .NET framework feature (as opposed to, say, Java, where it is only a compile-time feature based on Type Erasure). So, in .NET, through reflection, it is possible to implement the latter "bypassing" the former (which, again, would be impossible in Java).
But the OP clearly does not need that.
After all, entries is a List<IEntry>. IOW, the entries container does not "know" the concrete type of its elements (since it is bound to an interface). So, if each element to be add already implements IEntry, then this would be enough:
void Foo(params IEntry[] objects)
{
var entries = new List<IEntry>();
foreach(var o in objects)
{
entries.Add(o);
}
...
}
OTOH, if those objects do not implement IEntry, then the OP just need a pure, ordinary, old-school list of untyped objects:
void Foo(params object[] objects)
{
var entries = new List<object>();
foreach(var o in objects)
{
entries.Add(o);
}
...
}
So using reflection in order to dynamically create a generic container, even if possible, seems to be overkill for this particular use case.
You can do it with reflection
var entryType = typeof(Entry<>);
Type[] typeArgs = { o.GetType() };
var genericType = entryType.MakeGenericType(typeArgs);
IEntry entry = (IEntry)Activator.CreateInstance(genericType);
You need a function of the form:
Func<Type, IEntry>
I would suggest adding a static function to the parent of Foo like this:
public static IEntry Make(Type type)
Inside that function, feel free to add whatever code makes sense to you:
if (type == typeof(string))
{
return new StringEntry(); //Obviously some special logic based on the type.
}
else
{
//Default logic
return (IEntry) Activator.CreateInstance(typeof(Entry<>).MakeGenericType(type));
}

How do I write a method that can output data from any class using generics?

I'm trying to write a custom method to populate a ListView control using Generics:
private void BindDataToListView(List<T> containerItems)
{
this.View = View.Details;
this.GridLines = true;
this.FullRowSelect = true;
if (this.Items.Count > 0)
this.Items.Clear();
this.BeginUpdate();
int i = 0;
foreach (T item in containerItems)
{
// do something
}
this.EndUpdate();
}
The parameter containerItems can have many items since I'm using generics. But I get stuck in the foreach loop. How do I access the values in containerItems?
Do I have to use reflection on each instance of T in the foreach loop? I think I do to retrieve the property name. But once I have the property name of the type T, how do I retrieve the value?
The most common way of doing this (with winforms) is via TypeDescriptor; this allow you to use things DataTable the same as classes; the "full" pattern is quite complex (and involves checking for IListSource, ITypedList, etc; however, the short version is; to get the available properties:
PropertyDescriptorCollection props = TypeDescriptor.GetProperties(typeof(T));
To get a named property:
PropertDescriptor prop = props[propName];
To get a value for an instance (sourceObject):
object val = prop.GetValue(sourceObject);
To render a value as a string (using the designated converter):
string s = prop.Converter.ConvertToString(val);
You could limit T to an interface, and use that interface in the iteration.
What does T represent ?
Like it is now, it is a generic type and it can be ... anything.
So, what I would do, is create an interface IListViewBindable or something like that. That interface could then have a method 'CreateListViewItem' for instance.
Then, I would change the method, so that a constraint is applied to your type-parameter T, saying that T should implement IListViewBindable, like this:
public void BindDataToListView<T>( List<T> containerItems ) where T : IListViewBindable
{}
In your BindDataToListView method, you could then do this:
foreach( T item in containerItems )
{
this.Items.Add (item.CreateListViewItem());
}
If the items in the list are of totally unconstrained type, then you can treat them as simply of type object. You call GetType() to get the type of the object. On that you can call GetProperties() to get an array of PropertyInfo objects. And on those you can call GetValue() to retrieve the value of the property.
If you already know the name of a property, just call GetProperty() to retrieve it:
string valueAsString = item.GetType().GetProperty("Something")
.GetValue(item, null).ToString();
I don't completely understand what you're asking, but I think that this will point you in the right direction. Please ask for clarification if it looks like it can help and it's unclear.
You can access a given property of an object using reflection via
object o;
PropertyInfo info = o.GetType().GetProperty().GetProperty("NameOfPropertyIWant");
and you can get the value via
object value = info.GetValue(o, null);
Now, if you're going to be accessing a property of the same name on objects of various types, you should consider adding an interface
public interface IHasThePropertyIWant {
object NameOfPropertyIWant { get; }
}
Then you can enforce this via
void BindDataToListView(List<T> containerItems) where T : IHasThePropertyIWant
and use it in the look like so
foreach (T item in containerItems) {
object o = item.NameOfPropertyIWant;
// do something with o
}
ObjectListView uses reflection to do exactly what you are trying to do: populate a ListView using reflection. You could save yourself a lot of trouble by using it. It has already solved all the tricky problems you are going to encounter on this path.
If you really, really want to do it yourself, Marc's answer is (of course) completely correct.

Categories

Resources