Foreach change property. What is PropertyInfo? - c#

I have been reading over old questions asked ans searching MSDN help but I cant really understand what a PropertyInfo is, specifically relating to the question of looping through an array list
c# foreach (property in object)... Is there a simple way of doing this?)
I made a simple class
public MyClass
{
public double myProperty; // etc
}
and then I add class objects to a list. I want to loop through the list, to change just a property of each object
foreach ( MyClass i in MyClassList)
{
foreach ( double myProperty in i.GetType().GetProperties() )
{
// do something
}
}
but I get an error. In the linked question (above) it says to use PropertyInfo instead of 'double. what is the PropertyInfo that should replace the 'double' of myProperry and what does it represent?

PropertyInfo simply represents the fact that a property is defined for that type; it isn't per-object - it is for the type. You don't need any instances to get a PropertyInfo.
First, however, note that myProperty is not currently a property: let's fix that first:
public MyClass
{
public double MyProperty {get;set;}
}
now we can find out about that property, either by asking about "all the properties it has", i.e.
PropertyInfo[] props = typeof(MyClass).GetProperties();
or an individual property, perhaps getting the name from configuration at runtime:
PropertyInfo prop = typeof(MyClass).GetProperty("MyProperty");
You can inspect a PropertyInfo for the name, type, attributes, etc - very useful for library code. However, in regular code the simplest option is just to use static C#:
foreach(MyClass obj in MyClassList) {
obj.MyProperty = 123.45;
}
if you need to do this via reflection, then you can use SetValue:
foreach(MyClass obj in MyClassList) {
prop.SetValue(obj, 123.45, null);
}
however, reflection is relatively slow unless you go to greater lengths. For example, another alternative for targeting the "I'll know the names at runtime" scenario would be FastMember; then you can do:
var accessor = TypeAccessor.Create(typeof(MyClass));
string propName = "MyProperty";
object value = 123.45;
foreach(MyClass obj in MyClassList) {
accessor[obj, propName] = value;
}
which will be much faster than raw reflection, while having more flexibility in terms of finding property-names at runtime.

You probably want this:
foreach (MyClass i in MyClassList)
{
foreach (var myProperty in i.GetType().GetProperty("myProperty") )
{
myProperty.SetValue(i, 1.23);
}
}
This is equivalent to:
foreach (MyClass i in MyClassList)
{
i.myProperty = 1.23;
}

GetProperties returns a collection of PropertyInfo Objects.
You then need to iterate (or search) that collection for the property you want.
See here for an example of using GetProperties()
http://rhondatipton.net/2010/02/28/using-getproperties-in-c/

Related

Get properties of properties

So, I am interested in getting all properties of a class via reflection ... and all properties of class-type properties (recursively).
I managed to get the first level of properties via reflections with a code like this:
foreach (var property in Target.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
var foobar = Factory.GetDealer(Target, property.Name);
}
and in the factory:
public static BaseDealer GetDealer(Object obj, string property)
{
var prop = obj.GetType().GetProperty(property);
if (prop == null)
{
return null;
}
if (prop.PropertyType.IsPrimitive)
{
return GetPrimitivDealer(obj, property, Type.GetTypeCode(prop.PropertyType));
}
if (prop.PropertyType.IsClass)
{
return new CompositeDealer(obj, prop);
}
return null;
}
Obviously (in my mind that is), I'd then have something like this in the CompositeDealer:
public CompositeDealer(Object obj, PropertyInfo propInfo)
{
ComponentDealers = new List<BaseDealer>();
Object compProp = propInfo.GetValue(obj); // The new "origin" object for reflection, this does not work
foreach (var property in compProp.GetType().GetProperties())
{
var dealer = Factory.GetDealer(compProp, property.Name);
if (dealer != null)
{
ComponentDealer.Add(dealer);
}
}
}
As noted in the comment, getting the new "base object" for reflection, that is to start the "second level" of reflection does not work, it returns null.
I really struggle at this stage although I came so far and am pretty close (I think).
Help me StackOverflow,
you're my only hope.
Edit:
So, answering the question what the data would look like:
class A {
int primitiveProp {get;}
}
class B {
A compositeProp {get;}
}
If I were to call the Factory on an instance of A, I'd make a PrimitiveDealer.
If we call it on an instance of B, I'd get a CompositeDealer, which in turn has a primitiveDealer.
Also note that I need the actual property object of the passed instance (since I need to manipulate it) rather than a new object.
Instead of calling different functions to get the properties of your object, dependent on the property type, the function should then call itself with an instance of the object we want to get the properties of.
object o = Activator.CreateInstance(property.PropertyType)
Recursively call the function which gets the properties of this object.
Edit: If you instead need the actual object, ensure to cast it to the correct type.
Type compProp = (Type)propInfo.GetValue(obj);

Using a property of T to create a new object of the property type with the property values?

I need a way to convert the properties of an object of type T to objects of the property type, and values as they are in T. My reason for doing this is so that I can check if the property is or inherits from IEnumerable (Lists, arrays, etc.), and if it does then I need to pass that IEnumerable as an object to be worked on. So far I have
foreach (var propInfo in obj.GetType().GetProperties())
{
var newObject = Activator.CreateInstance(propInfo.PropertyType, propInfo.GetValue(obj));
if (ObjectProcessing.ImplementsIEnumerable(newObject))
{
ObjectProcessing.ObjectQueue.Enqueue(newObject);
}
}
Which unfortunately doesn't work. I cant use CreatInstance<T> because it seems the compiler assumes T is the T in the method signature, which is the source object not the target object.
The question looks like a XY problem. What is the XY Problem?
You do not need to create an instance of the object to see if it implements or is IEnumerable. Let me build upon what you have so far
// This is the example object
public class MyClass {
public IEnumerable A{ get;set;}
public List<int> B{get;set;}
}
var myClass = new MyClass();
foreach (var propInfo in myClass.GetType().GetProperties()) {
var typeOfProperty = propInfo.PropertyType;
var isIEnuerableOrInheritingFromIt = typeof(IEnumerable).IsAssignableFrom(typeOfProperty);
if (isIEnuerableOrInheritingFromIt) {
var objectThatImplementsIEnumerable = propInfo.GetValue(myClass);
// Do stuff with it
}
}

c# reflection - getting list of properties from a PropertyInfo

So, as the heading says, I have an object which is propertyInfo. What I want to get is that property, but I can't seem to find a way to do it.
Firstly I had this method:
public object GetPropertyInfo(object parent, String propertyName)
{
object propInf = null;
PropertyInfo[] propList = parent.GetType().GetProperties();
foreach (PropertyInfo pInf in propList)
{
if (propertyName == pInf.Name)
{
propInf = pInf;
}
}
return propInf;
}
And it works rather well, assuming the supplied 'parent' object is a regular class and not a reflected type.
But some of the properties returned themselves contain properties that I want to access. In these instances, I need to feed the PropertyInfo back into this method and get another PropertyInfo for the property. But if I put a PropertyInfo object into this method, it just returns me a property list of PropertyInfo (as you might imagine).
I have read up on it and it seems that what I may want is the 'GetValue' method of the PropertyInfo class. I'm a little unsure of it though since I can't seem to parse what it is that the method requires.
Even so, I wrote it as such:
public object GetPropertyInfo(object parent, String propertyName)
{
object propInf = null;
object o = null;
if (parent is PropertyInfo)
{
PropertyInfo p = (parent as PropertyInfo);
o = p.GetValue(p, null);
}
else
o = parent;
PropertyInfo[] propList = o.GetType().GetProperties();
foreach (PropertyInfo pInf in propList)
{
if (propertyName == pInf.Name)
{
propInf = pInf;
}
}
return propInf;
}
Obviously I hoped the second one would work. It passes through the 'if' statement fine, acknowledging that it is a PropertyInfo type, but then the next part provides an exception which is the following:
TargetException: Object does not match target type.
Maybe I made a mistake with the 'GetValue' since I'm not entirely familiar with it, but if I could do it without specifying a type, that would be great.
Assuming I understand what you are trying to do:
PropertyInfo represents a property of a class without being aware of the instance of the class whose property is being inspected.
GetValue method, however, can provide you the value of the property for a given instance.
object value = somePropertyInfo.GetValue(someInstance);
// where someInstance is of the type which has someProperty's represented property.
If you want the properties of the Type of the property you are currently inspecting you can use PropertyInfo.PropertyType.GetProperties(); but this will only get you the properties of the Type of the property and not the concrete (maybe derived) Type that it contains.

check If type is a list returns false

I was trying to process a generic class with properties that are List<T>. However it does not work when checking the property using IsAssignableFrom.
Code Snippet:
var type = model.GetType();
var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
int colorIndex = 0;
foreach (var property in properties)
{
if (typeof(List<>).IsAssignableFrom(property.PropertyType))
{
//codes here
}
}
Am I missing something here? Why is it not treating the property as List even it is a list?
In your model object you have properties with specific types, for example List<string>, List<int> or something similar. I your code however you are testing for open generic type. These types are not the same, so you do not get a match in if statement. To fix that you should use function GetGenericTypeDefinition() to get underlying open generic type:
foreach (var property in properties)
{
if (property.PropertyType.IsGenericType &&
typeof(List<>).IsAssignableFrom(property.PropertyType.GetGenericTypeDefinition()))
{
//codes here
}
}
You could try to check if item implements IList so make the check against the "contract" rather than the concrete class :
if (typeof(IList).IsAssignableFrom(property.PropertyType)
{
}

Reflection: casting reflected type to generic with type as string and iterating over it

I have scoured around StackOverflow and found multiple related questions, but none that answers it 'completely'. I might be wrong in my understanding, but wanted to check it -
I have a class
public class Foo
{
public List<Bar> Bars = new List<Bar>();
}
public class Bar
{
}
Due to some reflection craziness happening, this List is getting passed only as an object -
Foo f = new Foo();
object o = f;
CheckItem(o, "Bars");
// CheckItem has no clue about Bar class and is thus passed the 'Bars' Field name
public void CheckItem(Object obj, string fieldName)
{
var value = obj.GetType().GetField(fieldName).GetValue(obj); // returns f.Bars into value as object
foreach (var bar in value.Bars) // won't compile as value is type object
}
so, I use MakeGenericType and Activator.CreateInstance magic
var genericClass = typeof(List<>).MakeGenericType(new[] {value.GetType().FieldType.GetGenericArguments()[0]}); // makes a generic of type List<Bar>
var o = Activator.CreateInstance(genericClass); // o is again of type object
foreach (var bar in o.Bars) // will fail again
SO - How do I call the foreach loop to iterate over the members. Every example I have seen around MakeGenericType ends at just creating the object o, none talks about how to access its members, esp in a foreach loop like above.
Appreciate any inputs.
Thanks
If you don't need to know about the element type, all you need to do is cast to IEnumerable:
var sequence = (IEnumerable) value;
foreach (var item in sequence)
{
// The type of the item variable is just object,
// but each value will be a reference to a Bar
}
(I'd strongly recommend using private fields and exposing properties instead, by the way - but that's a different matter.)

Categories