Generic reflection, how to get a list? - c#

I have the following piece of code:
var prop = FindEntityProperty(entityName);
if(prop==null)
{
throw new InvalidOperationException("entityName: " + entityName);
}
var db = new DatabaseContext();
Type returnType = prop.PropertyType;
var col = (prop.GetValue(db) as ???);
Data = col.ToList(); //or something IEnumerable<?>
Situation looks that, I have PropertyInfo named prop here).
I'm sure this property is DbSet<Τ>. I don't know what type is T (only that it's a class). But because it's generic DbSet, it can be treated like a generic IEnumarble.
So, because propertyInfo.GetValue() return a simple object, Ι need to cast my collection.
How can I do this?
I know it's a bad practice in programming. Here I'm doing it only for learning reflection.

I've had a similar problem like that, i wanted to create a method that gives me the object back from the database, so created this piece of code.
I hope this helps you:
Put this into your DatabaseContainer:
public IEnumerable<TEntity> Find<TEntity>(Dictionary<string, object> findValues = null) where TEntity : EntityObject
{
var entities = this.CreateObjectSet<TEntity>().ToList();
if (findValues!= null && findValues.Count > 0)
{
foreach (var item in findValues)
{
if(item.Value != null)
entities = entities.DynamicContains<TEntity>(item.Key, item.Value);
}
}
return entities;
}
And put this into a extention class:
public static List<TEntity> DynamicContains<TEntity>(this IEnumerable<TEntity> entities, string propertyName, object item)
{
List<TEntity> comparingEntities = new List<TEntity>();
foreach (var obj in entities)
{
var property = obj.GetType().GetProperty(propertyName);
if (property.PropertyType == typeof(String) && ((string)property.GetValue(obj, new object[] { })).ToLower().Contains(item.ToString().ToLower()))
comparingEntities.Add(obj);
if (property.PropertyType == typeof(Boolean) && ((bool)property.GetValue(obj, new object[] { })) == (bool)item)
comparingEntities.Add(obj);
}
return comparingEntities;
}
Usage:
Dictionary<string, object> findValues = new Dictionary<string, object>();
findValues.Add("Name", "Tom");
findValues.Add("Age", 4);
var list1 = db.Find<Person>(findValues); // Returns a list of persons that includes the find values.
var list2 = db.Find<Person>() // Returns all persons in the database.

Related

Deep Clone of code first EF Entity

I am attempting a Generic Deep Clone Routine for code first Entity Framework entities.
I've cracked it for the standard System property types but am having trouble with Proxy Entities (defined with virtual) i.e.
[EntityLookup]
public virtual Person { get; set; }
[EntityLookup] is one of my own attributes that helps further define the Association.
If I remove the "virtual" keyword, my routine can update the destination entity property no problem (but I lose the additional EF functionality)
With virtual I get the following error;
System.Reflection.TargetException: 'Object does not match target type.'
I believe it's all to do with EF's Proxy class but I'm not sure how to cast the original entity so I can set it on the destination.
Below are the essentials of the Clone routine for this issue;
public static void CloneProperties<T>(T Original, T Destination)
{
PropertyInfo[] props = Original.GetType().GetProperties();
foreach (var propertyInfo in props)
{
if (propertyInfo.PropertyType.Namespace == "System" || propertyInfo.PropertyType.IsEnum)....
else
{
if (Destination.PropertyHasCustomAttribute (propertyInfo.Name, typeof(EntityLookupAttribute)))
{
var pv = propertyInfo.GetValue(Original, null);
propertyInfo.SetValue(Destination, pv, null);
}
}
}
}
It's the "propertyInfo.SetValue(Destination, pv, null);" that generates the error when the entity is declared virtual.
Any help on getting it to work will be gratefully accepted
Best Regards
Lance
In addition and in a similar vein I am now attempting to clone the child collections in my entity.
I'm iterating over the source property collection and need to add missing records to the destination properties collection
the a.Add(targetEntity); line is giving the following error;
"The best overloaded method match for 'System.Collections.ObjectModel.Collection<FmCosting.Entities.CsJobDetail>.Add(FmCosting.Entities.CsJobDetail)' has some invalid arguments"
The relevant code is;
if (dest.PropertyHasCustomAttribute(propertyInfo.Name, typeof(EntityChildCollectionAttribute)))
{
var source = propertyInfo.GetValue(original, null) as ICollection;
var target = propertyInfo.GetValue(dest, null) as ICollection;
foreach (dynamic sourceEntity in source)
{
var found = false;
object targetEntity = null;
foreach (dynamic tEntity in target)
{
if (sourceEntity.IdentityGuid == tEntity.IdentityGuid)
{
found = true;
targetEntity = tEntity;
continue;
}
}
if (!found)
{
var t = sourceEntity.GetType();
targetEntity = Activator.CreateInstance(t);
}
sourceEntity.CloneMeToProvidedEntity(targetEntity);
if (!found)
{
dynamic a = target;
a.Add(targetEntity);
}
}
//propertyInfo.SetValue(Destination, pv, null);
}
Any further help will be gratefully received
Best Regards
Lance
The concrete type for your destination object may be different from T, for this reason you have to use a PropertyInfo of destination and not of original:
public static void CloneProperties<T>(T original, T destination)
{
var originalType = original.GetType();
var destinationType = destination.GetType();
PropertyInfo[] props = originalType.GetProperties();
foreach (var propertyInfo in props)
{
if (propertyInfo.PropertyType.Namespace == "System" || propertyInfo.PropertyType.IsEnum)
{
// ....
}
else
{
if (destination.PropertyHasCustomAttribute (propertyInfo.Name, typeof(EntityLookupAttribute)))
{
var pv = propertyInfo.GetValue(original, null);
var destinationProperty = destinationType.GetProperty(propertyInfo.Name);
destinationProperty.SetValue(destination, pv, null);
}
}
}
}
Note:
Another option is to revert to compile time types, so both objects uses properties of T avoiding derived types that may be returned from GetType():
public static void CloneProperties<T>(T original, T destination)
{
PropertyInfo[] props = typeof(T).GetProperties();
foreach (var propertyInfo in props)
{
if (propertyInfo.PropertyType.Namespace == "System" || propertyInfo.PropertyType.IsEnum)
{
// ....
}
else
{
if (destination.PropertyHasCustomAttribute (propertyInfo.Name, typeof(EntityLookupAttribute)))
{
var pv = propertyInfo.GetValue(original, null);
propertyInfo.SetValue(destination, pv, null);
}
}
}
}
I got the collection clone working using IList, here is the relevant code if it helps anybody else.
if (dest.PropertyHasCustomAttribute(propertyInfo.Name, typeof(EntityChildCollectionAttribute)))
{
var source = propertyInfo.GetValue(original, null) as IList;
var target = propertyInfo.GetValue(dest, null) as IList;
foreach (dynamic sourceEntity in source)
{
var found = false;
object targetEntity = null;
foreach (dynamic tEntity in target)
{
if (sourceEntity.IdentityGuid != tEntity.IdentityGuid) continue;
found = true;
targetEntity = tEntity;
break;
}
if (!found)
{
var b = propertyInfo.PropertyType.GetGenericArguments()[0];
targetEntity = Activator.CreateInstance(b);
}
sourceEntity.CloneMeToProvidedEntity(targetEntity);
if (!found)
{
target.Add(targetEntity);
}
}
}

Find shared type among set of values

Given a passed-in IEnumerable, is there any built-in method to return a best-matching base type for all the items in the IEnumerable, that handles nullable/non-nullable types and inheritance?
Something like this:
var hs = new HashSet<object> {1,2,3,null};
Type t = GetSharedType(hs); //returns typeof(int?)
hs = new HashSet<object> {new BaseClass(), new DerivedClass()};
t = GetSharedType(hs); //returns typeof(BaseClass)
hs = new HashSet<object> {"1", 1};
t = GetSharedType(hs); //returns typeof(object) or null
(I am aware that I can write my own; my question is if there is something built-in).
No, there is no built-in mechanism to do this. You can combine several reflection APIs.
First you can retrieve real types for each object in collection with GetType():
IEnumerable<Type> realTypes = hs.Select(o => o.GetType());
Now you will have collection of Type class that have BaseType property and GetInterfaces() method. Ypu can use this code to get all hierarchy for each type:
public static IEnumerable<Type> GetParentTypes(this Type type)
{
// is there any base type?
if ((type == null) || (type.BaseType == null))
{
yield break;
}
// return all implemented or inherited interfaces
foreach (var i in type.GetInterfaces())
{
yield return i;
}
// return all inherited types
var currentBaseType = type.BaseType;
while (currentBaseType != null)
{
yield return currentBaseType;
currentBaseType= currentBaseType.BaseType;
}
}
You can use it to get collection of hierarchies:
IEnumerable<IEnumerable<Type>> baseTypes = realTypes.Select(t => t.GetParentTypes());
Next step is to merge all this list to have only intersected values. You can do it with Enumerable.Intersect method and this code:
public static IEnumerable<T> IntersectAllIfEmpty<T>(params IEnumerable<T>[] lists)
{
IEnumerable<T> results = null;
lists = lists.Where(l => l.Any()).ToArray();
if (lists.Length > 0)
{
results = lists[0];
for (int i = 1; i < lists.Length; i++)
results = results.Intersect(lists[i]);
}
else
{
results = new T[0];
}
return results;
}
Finally, we have:
IEnumerable<Type> realTypes = hs.Select(o => o.GetType());
IEnumerable<IEnumerable<Type>> baseTypes = realTypes.Select(t => t.GetParentTypes());
IEnumerable<Type> inersectedBaseTypes = IntersectAllIfEmpty(baseTypes);
Then we can use Type.IsAssignableFrom() method to iterate each type and ensure that one of them is assignable only from themself:
Type mostConcreteType = inersectedBaseTypes.Where(t => inersectedBaseTypes.Count(bt => t.IsAssignableFrom(bt)) == 1).FirstOrDefault();
No, there is no built in type for doing this. As you have identified by yourself that you have to write by your own. Something like
public static Type GetEnumerableType<T>(this IEnumerable<T> enumerable)
{
return typeof(T);
}

How to return correctly cast IEnumerable

This method works, except it returns List<object> when what I really want is List<Resource> when specificType is Resource (and List<YYY> when specificType is YYY, and so on).
How can I rearrange the method signature to return List<specificType>? Then, is there a better way to do this? The items in List<object> are deserialized from many different types in this assembly. I'm trying to create lists of ActualType and return that list to caller. Hope this makes sense.
private static ICollection<object> GetSpecificTypeList(Dictionary<string, List<object>> objectListDictionary, Type specificType)
{
Contract.Requires(objectListDictionary != null);
Contract.Requires(specificType != null);
var typeFullName = specificType.FullName;
var typedCollection = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(specificType));
var collection = objectListDictionary.SingleOrDefault(q => q.Key.Equals(typeFullName)).Value;
foreach (var obj in collection)
{
typedCollection.Add(Convert.ChangeType(obj, specificType));
}
return collection;
}
var resourceList = GetSpecificTypeList(package.FilesDictionary, typeof(Resource));
Would dynamic help?
Make the method generic:
private static ICollection<T> GetSpecificTypeList<T>(Dictionary<string, List<object>> objectListDictionary)
{
Contract.Requires(objectListDictionary != null);
Contract.Requires(specificType != null);
var list = new List<T>();
var collection = objectListDictionary.SingleOrDefault(q => q.Key.Equals(typeof(T).FullName)).Value;
foreach (var obj in collection.OfType<T>())
{
list.Add(obj);
}
return list;
}
How can I rearrange the method signature to return List<specificType>?
Make the method generic:
private static ICollection<T> GetSpecificTypeList<T>(Dictionary<string, List<object>> objectListDictionary)
{
Contract.Requires(objectListDictionary != null);
Contract.Requires(specificType != null);
var typeFullName = typeof(T).FullName;
//var collection = objectListDictionary.SingleOrDefault(q => q.Key.Equals(typeFullName)).Value;
var collection = objectListDictionary[typeFullName];
var typedCollection = collection.OfType<T>().ToList();
return typedCollection;
}
Now your calling syntax is:
var resourceList = GetSpecificTypeList<Resource>(package.FilesDictionary);
A few other suggestions:
Consider a Dictionary<Type, List<object> instead - using s atring to identify a type can be tricky
You may even be able to use List<object> and filter using list.OfType<T> (assuming that the key for each object collection is its type.
Here is my modified version of Dave's propsal using yield return and IEnumerable, which enables lazy evaluation:
private static IEnumerable<T> GetSpecificTypeList<T>(Dictionary<string, List<object>> objectListDictionary)
{
Contract.Requires(objectListDictionary != null);
var collection = objectListDictionary.SingleOrDefault(q => q.Key.Equals(typeof(T).ToString())).Value;
foreach (var obj in collection)
{
yield return (T) Convert.ChangeType(obj, typeof(T));
}
}

Adding new T to empty List<T> using reflection

I'm attempting to set add a new instance of an Officer class to a potentially empty list using reflection.
These are my classes
public class Report(){
public virtual ICollection<Officer> Officer { get; set; }
}
public class Officer(){
public string Name{ get; set; }
}
Simplified code snippet:
Report report = new Report()
PropertyInfo propertyInfo = report.GetType().GetProperty("Officer");
object entity = propertyInfo.GetValue(report, null);
if (entity == null)
{
//Gets the inner type of the list - the Officer class
Type type = propertyInfo.PropertyType.GetGenericArguments()[0];
var listType = typeof(List<>);
var constructedListType = listType.MakeGenericType(type);
entity = Activator.CreateInstance(constructedListType);
}
//The entity is now List<Officer> and is either just created or contains a list of
//Officers
//I want to check how many officers are in the list and if there are none, insert one
//Pseudo code:
if (entity.count = 0)
{
entity.add(new instance of type)
}
Much appreciated!
Use:
object o = Activator.CreateInstance(type); // "type" is the same variable you got a few lines above
((IList)entity).add(o);
You have two options:
1) Using dynamic:
dynamic list = entity;
if (list.Count = 0)
{
list.Add(new instance of type)
}
2) Using Reflection:
var countProp = entity.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance).First(p => p.Name == "Count");
var count = (int)countProp.GetValue(entity,null);
if(count == 0)
{
var method = entity.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public).First(m => m.Name == "Add");
method.Invoke(entity,new instance of type);
}
This isn't quite what you asked for but may accomplish the same task.
public static ICollection<T> EnsureListExistsAndHasAtLeastOneItem(ICollection<T> source)
where T : Officer, new()
{
var list = source ?? new List<T>();
if( list.Count == 0 ) list.Add(new T());
return list;
}
If Officer doesn't have a default constructor then you could add a factory callback
public static ICollection<T> EnsureListExistsAndHasAtLeastOneItem
(ICollection<T> source, Func<T> builder)
where T : Officer
{
var list = source ?? new List<T>();
if( list.Count == 0 ) list.Add(builder());
return list;
}
Just type your entity appropriately as a List<Officer> (or an appropriately more abstract type (such as IList)) and use as normal:
entity = Activator.CreateInstance(constructedListType) as IList;
But no need to check whether to insert or not, just insert:
entity.Insert(0, officer);
I'm assuming (based on the fact that you already know how to create instances using reflection) you're not having trouble creating the instance of type Officer.
Edit after re-reading over your question: This doesn't directly answer your question but is rather a suggestion of a different implementation.
You can easily get by without using reflection:
public class TestContainer<T>
{
private readonly List<T> _list;
public TestContainer()
{
_list = new List<T>();
}
public void Add()
{
_list.Add(default(T));
}
}
Then calling e.g.:
var t = new TestContainer<YourClass>();
t.Add();
t.Add();
t.Add();
you will have a list of 3 instances of YourClass by their default value

Get properties and values from unknown object

From the world of PHP I have decided to give C# a go. I've had a search but can't seem to find the answer of how to do the equivalent to this.
$object = new Object();
$vars = get_class_vars(get_class($object));
foreach($vars as $var)
{
doSomething($object->$var);
}
I basically have a List of an object. The object could be one of three different types and will have a set of public properties. I want to be able to get a list of the properties for the object, loop over them and then write them out to a file.
I'm thinking this has something to do with c# reflection but it's all new to me.
Any help would be greatly appreciated.
This should do it:
Type myType = myObject.GetType();
IList<PropertyInfo> props = new List<PropertyInfo>(myType.GetProperties());
foreach (PropertyInfo prop in props)
{
object propValue = prop.GetValue(myObject, null);
// Do something with propValue
}
void Test(){
var obj = new{a="aaa", b="bbb"};
var val_a = obj.GetValObjDy("a"); //="aaa"
var val_b = obj.GetValObjDy("b"); //="bbb"
}
//create in a static class
static public object GetValObjDy(this object obj, string propertyName)
{
return obj.GetType().GetProperty(propertyName).GetValue(obj, null);
}
Yes, Reflection would be the way to go. First, you would get the Type that represents the type (at runtime) of the instance in the list. You can do this by calling the GetType method on Object. Because it is on the Object class, it's callable by every object in .NET, as all types derive from Object (well, technically, not everything, but that's not important here).
Once you have the Type instance, you can call the GetProperties method to get the PropertyInfo instances which represent the run-time informationa about the properties on the Type.
Note, you can use the overloads of GetProperties to help classify which properties you retrieve.
From there, you would just write the information out to a file.
Your code above, translated, would be:
// The instance, it can be of any type.
object o = <some object>;
// Get the type.
Type type = o.GetType();
// Get all public instance properties.
// Use the override if you want to classify
// which properties to return.
foreach (PropertyInfo info in type.GetProperties())
{
// Do something with the property info.
DoSomething(info);
}
Note that if you want method information or field information, you would have to call the one of the overloads of the GetMethods or GetFields methods respectively.
Also note, it's one thing to list out the members to a file, but you shouldn't use this information to drive logic based on property sets.
Assuming you have control over the implementations of the types, you should derive from a common base class or implement a common interface and make the calls on those (you can use the as or is operator to help determine which base class/interface you are working with at runtime).
However, if you don't control these type definitions and have to drive logic based on pattern matching, then that's fine.
well, in C# it's similar.
Here's one of the simplest examples (only for public properties):
var someObject = new { .../*properties*/... };
var propertyInfos = someObject.GetType().GetProperties();
foreach (PropertyInfo pInfo in propertyInfos)
{
string propertyName = pInfo.Name; //gets the name of the property
doSomething(pInfo.GetValue(someObject,null));
}
One line solution using Linq...
var obj = new {Property1 = 1, Property2 = 2};
var property1 = obj.GetType().GetProperties().First(o => o.Name == "Property1").GetValue(obj , null);
To get specific property value from property name
public class Bike{
public string Name {get;set;}
}
Bike b = new Bike {Name = "MyBike"};
to access property value of Name from string name of property
public object GetPropertyValue(string propertyName)
{
//returns value of property Name
return this.GetType().GetProperty(propertyName).GetValue(this, null);
}
You can use GetType - GetProperties - Linq Foreach:
obj.GetType().GetProperties().ToList().ForEach(p =>{
//p is each PropertyInfo
DoSomething(p);
});
Here's something I use to transform an IEnumerable<T> into a DataTable that contains columns representing T's properties, with one row for each item in the IEnumerable:
public static DataTable ToDataTable<T>(IEnumerable<T> items)
{
var table = CreateDataTableForPropertiesOfType<T>();
PropertyInfo[] piT = typeof(T).GetProperties();
foreach (var item in items)
{
var dr = table.NewRow();
for (int property = 0; property < table.Columns.Count; property++)
{
if (piT[property].CanRead)
{
var value = piT[property].GetValue(item, null);
if (piT[property].PropertyType.IsGenericType)
{
if (value == null)
{
dr[property] = DBNull.Value;
}
else
{
dr[property] = piT[property].GetValue(item, null);
}
}
else
{
dr[property] = piT[property].GetValue(item, null);
}
}
}
table.Rows.Add(dr);
}
return table;
}
public static DataTable CreateDataTableForPropertiesOfType<T>()
{
DataTable dt = new DataTable();
PropertyInfo[] piT = typeof(T).GetProperties();
foreach (PropertyInfo pi in piT)
{
Type propertyType = null;
if (pi.PropertyType.IsGenericType)
{
propertyType = pi.PropertyType.GetGenericArguments()[0];
}
else
{
propertyType = pi.PropertyType;
}
DataColumn dc = new DataColumn(pi.Name, propertyType);
if (pi.CanRead)
{
dt.Columns.Add(dc);
}
}
return dt;
}
This is "somewhat" overcomplicated, but it's actually quite good for seeing what the outcome is, as you can give it a List<T> of, for example:
public class Car
{
string Make { get; set; }
int YearOfManufacture {get; set; }
}
And you'll be returned a DataTable with the structure:
Make (string)
YearOfManufacture (int)
With one row per item in your List<Car>
This example trims all the string properties of an object.
public static void TrimModelProperties(Type type, object obj)
{
var propertyInfoArray = type.GetProperties(
BindingFlags.Public |
BindingFlags.Instance);
foreach (var propertyInfo in propertyInfoArray)
{
var propValue = propertyInfo.GetValue(obj, null);
if (propValue == null)
continue;
if (propValue.GetType().Name == "String")
propertyInfo.SetValue(
obj,
((string)propValue).Trim(),
null);
}
}
I haven't found this to work on, say Application objects. I have however had success with
var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
string rval = serializer.Serialize(myAppObj);
You can try this:
string[] arr = ((IEnumerable)obj).Cast<object>()
.Select(x => x.ToString())
.ToArray();
Once every array implements IEnumerable interface
public Dictionary<string, string> ToDictionary(object obj)
{
Dictionary<string, string> dictionary = new Dictionary<string, string>();
Type objectType = obj.GetType();
IList<PropertyInfo> props = new List<PropertyInfo>(objectType.GetProperties());
foreach (PropertyInfo prop in props)
{
object propValue = prop.GetValue(obj, null);
dictionary.Add(prop.Name, propValue.ToString());
}
return dictionary;
}
/// get set value field in object to object new (two object field like )
public static void SetValueObjectToObject (object sourceObj , object resultObj)
{
IList<PropertyInfo> props = new List<PropertyInfo>(sourceObj.GetType().GetProperties());
foreach (PropertyInfo prop in props)
{
try
{
//get value in sourceObj
object propValue = prop.GetValue(sourceObj, null);
//set value in resultObj
PropertyInfo propResult = resultObj.GetType().GetProperty(prop.Name, BindingFlags.Public | BindingFlags.Instance);
if (propResult != null && propResult.CanWrite)
{
propResult.SetValue(resultObj, propValue, null);
}
}
catch (Exception ex)
{
// do something with Ex
}
}
}

Categories