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
Related
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 ;)
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!
A dynamic object is generated using a Json deserializing component (Jil) I am using, and I am able to access the properties directly. But I don't know their names in advance, so I am trying to get the names with reflection. I tried doing this:
var props = myDynObj.GetType().GetProperties();
but the page times out. Doesn't give me anything in debugger, just sits there doing nothing, or something and not telling me.
This even happens when I even do this:
var t = myDynObj.GetType();
But when I do this, it works:
var val = myDynObj.MyStaticValue1
Just can't really do anything else with it. Anyonw know why, and how I can get this to work?
Please allow me to note:
Before I get started, if you don't know the members already when you're parsing JSON, you should not be parsing into a dynamic object. The built-in .Net JavaScriptConverter class can parse JSON into a IDictionary<string, object> which would be much better for you.
However, if you still want to use dynamic objects for some reason:
If you want to stick with your current library: I dont know how exactly that class is working, and I'm not saying this is the best solution, but by looking at the source it jumps out to me that you can grab a list of the ObjectMembers keys using reflection.
Type t = typeof(JsonObject)
var fi = t.GetField("ObjectMembers", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
IEnumerable<string> keys = ((Dictionary<string, JsonObject>)fi.GetValue(obj)).Keys;
Edit: Seeing that JsonObject implements IDynamicMetaObjectProvider, the following method mentioned in this question will also work on it:
public static IEnumerable<string> GetMemberNames(object target, bool dynamicOnly = false)
{
var tList = new List<string>();
if (!dynamicOnly)
{
tList.AddRange(target.GetType().GetProperties().Select(it => it.Name));
}
var tTarget = target as IDynamicMetaObjectProvider;
if (tTarget !=null)
{
tList.AddRange(tTarget.GetMetaObject(Expression.Constant(tTarget)).GetDynamicMemberNames());
}else
{
if (ComObjectType != null && ComObjectType.IsInstanceOfType(target) && ComBinder.IsAvailable)
{
tList.AddRange(ComBinder.GetDynamicDataMemberNames(target));
}
}
return tList;
}
If you are open to trying a different JSON converter: try this class here: http://pastie.org/private/vhwfvz0pg06zmjqirtlxa I'm not sure where I found it (I can't take credit) but here is an example of how to use it how you want:
// Create dynamic object from JSON string
dynamic obj = DynamicJsonConverter.CreateSerializer().Deserialize("JSON STRING", typeof(object));
// Get json value
string str = obj.someValue;
// Get list of members
IEnumerable<string> members = (IDictionary<string, object>)obj).Keys
Personally I like using the second one, it is simple and easy to use - and builds off of the built in .Net JSON parser.
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.
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.