How can I access CssStyleCollection class properties ( most of all I interesting its key-value collection) using reflection?
// this code runns inside class that inherited from WebControl
PropertyInfo[] properties = GetType().GetProperties();
//I'am not able to do something like this
foreach (PropertyInfo property in properties)
{
if(property.Name == "Style")
{
IEnumerable x = property.GetValue(this, null) as IEnumerable;
...
}
}
Here's the syntax for getting the Style property via reflection:
PropertyInfo property = GetType().GetProperty("Style");
CssStyleCollection styles = property.GetValue(this, null) as CssStyleCollection;
foreach (string key in styles.Keys)
{
styles[key] = ?
}
Note that CssStyleCollection doesn't implement IEnumerable (it implements the indexing operator), so you can't cast it to that. If you want to get an IEnumerable, you could extract the keys using styles.Keys, and the values:
IEnumerable<string> keys = styles.Keys.OfType<string>();
IEnumerable<KeyValuePair<string,string>> kvps
= keys.Select(key => new KeyValuePair<string,string>(key, styles[key]));
Related
I have an object with properties. Some properties are generic list. For example IList<IArticle> or IList<IProduct> and so on.
I iterate over all properties in the object with myObject.GetType().GetProperties() and search for properties which are from type IList.
I can identify the IList-properties and would like to iterate over the list. But there is my problem. I can't cast the listProperty (which is of type object) into generic list. The problem is that the properties are different generic types. To cast into IList will work only for the property which are from type IList<IArticle>, but not for the rest like IList<IProdukt>...
Cast into IList<object> is always null.
Here is a example code:
foreach (var myProperty in myObject.GetType().GetProperties())
{
//get generic property (type IList)
if (myProperty.PropertyType.IsGenericType)
{
PropertyInfo propInfo = myObject.GetType().GetProperty(myProperty.Name);
Type propType = myObject.GetType().GetProperty(myProperty.Name).PropertyType;
var listProperty = propInfo.GetValue(myProperty);
foreach (var test in (listProperty as IList<???>))
{
//Do some magic
}
}
}
Here is the solution to iterate over the list. Just cast to IEnumerable.
Don't forget to include using System.Collections;.
foreach (var myProperty in myObject.GetType().GetProperties())
{
//get generic property (type IList)
if (myProperty.PropertyType.IsGenericType)
{
var listProperty = myProperty.GetValue(myObject) as IEnumerable;
foreach (var test in listProperty)
{
//Do some magic
}
}
}
I have Repository<T> where T is derrived form of BaseEntity class.
Repository<T> has IQueryable<T> Table property. I need to make a call to FirstOrDefault method in the Table property.
till now i have got to list the Repositories, but stuck making call to the method using reflection.
private IEnumerable<object> GetEnumerableRepositoryOf<T>(params object[] constructorArgs) where T : class
{
List<object> objects = new List<object>();
foreach (Type type in
Assembly.GetAssembly(typeof(T)).GetTypes()
.Where(myType => myType.IsClass && !myType.IsAbstract && myType.IsSubclassOf(typeof(T))))
{
objects.Add(Activator.CreateInstance(typeof(Repository<>).MakeGenericType(type), constructorArgs));
}
return objects;
}
var repoList = GetEnumerableRepositoryOf<BaseEntity>(constructorArgs);
foreach (var repo in repoList)
{
// call FirstOrDefault() here
}
So your list is Repository<X> where X is T, and the property Table is IQueryable<X>. As we are lacking type knowledge of X at compile time, reflection it is.
So get the property with reflection by using the non-generic interface, then apply cast to T, and do your FirstOrDefault.
Here's how you can do it:
foreach (var repo in repoList)
{
var firstOrNull =
(repo.GetType().GetProperty("Table").GetValue(repo) as IQueryable)
.Cast<BaseEntity>().FirstOrDefault();
}
If using entity framework (which does not support this kind of casting above):
foreach (var repo in repoList)
{
var enumerator =
(repo.GetType().GetProperty("Table").GetValue(repo) as IEnumerable)
.GetEnumerator();
var firstOrNull = (BaseEntity) (enumerator.MoveNext() ?
enumerator.Current : default(BaseEntity));
}
EDIT
I am sorry, my question was not clear. I want to add to the list not only the property name but its value
I want to iterate through all the properties of a class and find all properties of a certain type and add them to a list. The code I use to iterate is:
List<CustomAttribute> attributes = new List<CustomAttribute>();
PropertyInfo[] properties = typeof(CustomClass).GetProperties();
foreach (PropertyInfo property in properties)
{
if (property.PropertyType == typeof(CustomAttribute))
{
//here I want to add property to list
}
}
Any ideas?
Thanks
public static List<PropertyInfo> PropertiesOfType<T>(this Type type) =>
type.GetProperties().Where(p => p.PropertyType == typeof(T)).ToList();
And you'd use it as follows:
var properties = typeof(CustomClass).PropertiesOfType<CustomAttribute>();
If what you need are the values of the properties of type T in a given instance then you could do the following:
public static List<T> PropertyValuesOfType<T>(this object o) =>
o.GetType().GetProperties().Where(p => p.PropertyType == typeof(T)).Select(p => (T)p.GetValue(o)).ToList();
And you'd use it as:
CustomClass myInstance = ...
var porpertyValues = myInstance.GetPropertyValuesOfType<CustomAttribute>();
Note that this just gives you the idea, you need to evaluate if dealing with properties with no getters is needed.
And last but not least, if you need the values and the property names, then you can build up a List of tuples to store the information:
public static List<Tuple<string, T>> PropertiesOfType<T>(this object o) =>
o.GetType().GetProperties().Where(p => p.PropertyType == typeof(T)).Select(p => new Tuple<string, T>(p.Name, (T)p.GetValue(o))).ToList();
Is there a way to distinguish between a regular collection property and a navigation property on an Entity-Framework class (Database-First)?
I'm currently checking if the object is ICollection and IsVirtual but I feel this could possibly trigger on a regular property that someone has declared as a virtual collection.
Question: Are there any other ways to distinguish Navigation Properties from others?
Context: I'm using this to compare values of any object, but I want it to ignore navigation properties (to ignore circular-references among other things).
foreach (var item in (IEnumerable)obj)
{
list2.MoveNext();
var item2 = list2.Current;
foreach (PropertyInfo propInfo in item.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
Object v1 = propInfo.GetValue(item);
Object v2 = propInfo.GetValue(item2);
Primitive = (v1 == null && v2 == null) || IsPrimitive(v1.GetType());
if (Primitive)
{
Assert.AreEqual(v1, v2);
}
else
{
// Ignore Navigation Properties
// Currently assuming Virtual properties to be Navigation...
if (propInfo.GetGetMethod().IsVirtual) continue;
CompareObjects(v1, v2);
}
}
}
Well, if you want to know the names of the navigation properties and the scalar properties related to an Entity, I suggest you use this code:
using (var db = new YourContext())
{
var workspace = ((IObjectContextAdapter)db).ObjectContext.MetadataWorkspace;
var itemCollection = (ObjectItemCollection)(workspace.GetItemCollection(DataSpace.OSpace));
var entityType = itemCollection.OfType<EntityType>().Single(e => itemCollection.GetClrType(e) == typeof(YourEntity));
foreach (var navigationProperty in entityType.NavigationProperties)
{
Console.WriteLine(navigationProperty.Name);
}
foreach (var property in entityType.Properties)
{
Console.WriteLine(property.Name);
}
}
One solution when using GetProperties() is to create an IEntity interface and apply it to all entities. Then you can skip over single entity navigation properties by checking if they implement IEntity and multiple entity navigation
if they are of type ICollection.
So in your foreach,
if (property.PropertyType.IsGenericType && property.PropertyType.GetGenericTypeDefinition() == typeof(System.Collections.Generic.ICollection<>)) continue;
if (property.PropertyType.GetInterfaces().Contains(typeof(IEntity))) continue;
Here is a simple method to return only updateable properties using this logic:
private IEnumerable<PropertyInfo> GetUpdateableProperties<T>(T entity) where T : IEntity
{
return entity.GetType().GetProperties(BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance | BindingFlags.SetProperty)
.Where(property =>
property.CanWrite &&
!property.PropertyType.GetInterfaces().Contains(typeof(IEntity)) &&
!(property.PropertyType.IsGenericType && property.PropertyType.GetGenericTypeDefinition() == typeof(ICollection<>))
);
}
I've written a custom attribute that I use on certain members of a class:
public class Dummy
{
[MyAttribute]
public string Foo { get; set; }
[MyAttribute]
public int Bar { get; set; }
}
I'm able to get the custom attributes from the type and find my specific attribute. What I can't figure out how to do is to get the values of the assigned properties. When I take an instance of Dummy and pass it (as an object) to my method, how can I take the PropertyInfo object I get back from .GetProperties() and get the values assigned to .Foo and .Bar?
EDIT:
My problem is that I can't figure out how to properly call GetValue.
void TestMethod (object o)
{
Type t = o.GetType();
var props = t.GetProperties();
foreach (var prop in props)
{
var propattr = prop.GetCustomAttributes(false);
object attr = (from row in propattr where row.GetType() == typeof(MyAttribute) select row).First();
if (attr == null)
continue;
MyAttribute myattr = (MyAttribute)attr;
var value = prop.GetValue(prop, null);
}
}
However, when I do this, the prop.GetValue call gives me a TargetException - Object does not match target type. How do I structure this call to get this value?
Your need to pass object itself to GetValue, not a property object:
var value = prop.GetValue(o, null);
And one more thing - you should use not .First(), but .FirstOrDefault(), because your code will throw an exception, if some property does not contains any attributes:
object attr = (from row in propattr
where row.GetType() == typeof(MyAttribute)
select row)
.FirstOrDefault();
You get array of PropertyInfo using .GetProperties() and call PropertyInfo.GetValue Method on each
Call it this way:
var value = prop.GetValue(o, null);