Get properties of properties - c#

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

Related

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.

Get Value Of PropertyInfo

I'm creating a small validation framework, I've a custom Validation Attribute which is assignable to methods and a IsValid property in ValidationCore class. When IsValid called inside the method my ValidationCore finds a caller method and get its attribute assigned to method. My custom Validation attribute has a property name named TypeToValidate. So when I find validation attribute I look for any types in class scope of that type. I don't have any problem till now, but the problem is when I want to get the value of property which I've to validate I don't have any instance of that class to get that property value. I don't know how can I handle this situation please help me.
This is my sample :
public class TestClass
{
public static TestModel Model { get; set; }
public static ModelValidator ModelState
{
get { return new ModelValidator(); }
}
[Validate(typeof(TestModel))]
public static void DoSomething()
{
if (ModelState.IsValid)
{
// Do something else....
}
}
}
Edit : This is my IsValid property
public virtual Boolean IsValid
{
get
{
// Get IsValid caller method
var method = GetCallerMethod();
// Get method attribute
var Attrib = GetMethodAttribute(typeof(ValidateAttribute), method);
// Get model to validate inside class scope
var modelProperty = GetModelToValidateInClassScope(Attrib, method);
if (modelProperty != null)
{
ValidateModel(modelProperty);
}
....
}
}
and here is ValidateModel method :
protected virtual void ValidateModel(PropertyInfo modelProperty)
{
// Here I've model property
// But I can't get its value
var model = modelProperty.GetValue(null, null);
var properties = model.GetType().GetProperties(
BindingFlags.FlattenHierarchy |
BindingFlags.Public |
BindingFlags.Instance |
BindingFlags.DeclaredOnly);
foreach (var propertyInfo in properties)
{
// Add error to error list
GetPropertyErrors(model, propertyInfo);
}
}
Thanks in advance.
You need an instance for which to get the property value of. It looks like you need to modify the method GetModelToValidateInClassScope so that it returns the instance of the model itself, along with the PropertyInfo.
If this method is changed so it looks something like this (note the new out parameter):
PropertyInfo GetModelToValidateInClassScope(Type attributeType, MethodInfo methodInfo, out object instance)
{
// same implementation as before ...
// assign the model to use,
// which is likely accessible from somewhere in the is method
instance = theModelInstanceFromThisMethod;
// .. or if the property is static, then uncomment the next line:
// instance = null;
// same return value as before ...
}
I'm just guessing here because you didn't provide the implementation of this method. If GetModelToValidateInClassScope doesn't have access to the model instance, then you'll have to get it from somewhere else.
Once you get the model instance, it could be used like the following. Note that ValidateModel has been modified so that it accepts the model instance as the first parameter.
...
// Get model to validate inside class scope
object instance; // <--- will hold the model instance
var modelProperty = GetModelToValidateInClassScope(Attrib, method, out instance);
if (modelProperty != null)
{
ValidateModel(instance, modelProperty); // <--- make sure to pass the instance along!
}
...
protected virtual void ValidateModel(object instance, PropertyInfo modelProperty)
{
// get value of instance property
var model = modelProperty.GetValue(instance, null);
...
}
Answer to the question actually asked
I don't have any problem till now, but the problem is when I want to get the value of property which I've to validate I don't have any instance of that class to get that property value.
If it's a static property, that's fine - just use null as the first argument:
// First argument is the instance: null as it's a static property
// Second argument is indexer arguments: null as we don't have any
var value = property.GetValue(null, null);
From the documentation:
Because static properties belong to the type, not individual objects, get static properties by passing null as the object argument.
Alternative approach
If you're just trying to get the TypeToValidate property from the Validate attribute, then you should have an instance of the attribute, and you can just cast to ValidateAttribute and retrieve the property directly.
Basically, it's not clear where properties really come into what you're trying to do. Your attribute is on a method rather than a property, and your attribute doesn't say which properties to validate...

Accessing inner type of ICollection<SomeInnerClass> through reflection in c#

I'm attempting to set a property on an object using reflection.
The property is an ICollection - if the Collection has not been instantiated, I want to get that done. My problems is that I'm having issues getting the inner type of the ICollection
This is my class
public class Report(){
public virtual ICollection<Officer> OfficerCollection { get; set; }
}
I'm trying to access the 'Officer' class defined below through reflection
public class Officer(){
public string Name{ get; set; }
}
Code snippet
Report report = new Report()
PropertyInfo propertyInfo = report.GetType().GetProperty("OfficerCollection");
object entity = propertyInfo.GetValue(report, null);
if (entity == null)
{
//How do I go about creating a new List<Officer> here?
}
Give this a whirl:
Report report = new Report();
PropertyInfo propertyInfo = report.GetType().GetProperty("Officer");
object entity = propertyInfo.GetValue(report, null);
if (entity == null)
{
Type type = propertyInfo.PropertyType.GetGenericArguments()[0];
Type listType = typeof(List<>).MakeGenericType(type);
var instance = Activator.CreateInstance(listType);
propertyInfo.SetValue(...);
}
First of all you have to get the of Officer property:
var propertyType = propertyInfo.PropertyType;
Then you to extract generic type parameter:
var genericType = propertyType.GetGenericArguments()[0];
After that invoke create a generic list:
var listType = typeof(List<>).MakeGenericType(genericType);
Finally create a new instance of generic list:
var listInstance = Activator.CreateInstance(listType);
and... Have fun ;)
EDIT:
It's nice to play sometimes with reflection, but I recommend you to do it this way:
public class Report()
{
private ICollection<Officer> officers;
public virtual ICollection<Officer> Officer
{
get
{
if(officers == null)
officers = new List<Officer>();
return officers;
}
set { officers = value; }
}
}
Ignoring the issue that this whole design sounds terrible, I'll try to answer your question. You can find the type of the property with Type type = ...GetProperty(...).PropertyType. If the type was a concrete type - instead of an interface as it currently is - you could then use System.Activator.CreateInstance(type, null) - where null means no constructor arguments - to create an instance of this concrete type. Given that your property type is actually an interface, you don't know whether you should be creating a list, array, collection or any other type that would satisfy this type. You would then need to use SetValue to assign the instance to the property, but of course we're not able to get this far.
You should take this information to reevaluate your design to not depend on reflection, and instead use generic parameterization (look at the new() constraint) and lazy initialization of properties (if you think that makes sense - we're not mind readers.)

How to detect if a property exists on an ExpandoObject?

In javascript you can detect if a property is defined by using the undefined keyword:
if( typeof data.myProperty == "undefined" ) ...
How would you do this in C# using the dynamic keyword with an ExpandoObject and without throwing an exception?
According to MSDN the declaration shows it is implementing IDictionary:
public sealed class ExpandoObject : IDynamicMetaObjectProvider,
IDictionary<string, Object>, ICollection<KeyValuePair<string, Object>>,
IEnumerable<KeyValuePair<string, Object>>, IEnumerable, INotifyPropertyChanged
You can use this to see if a member is defined:
var expandoObject = ...;
if(((IDictionary<String, object>)expandoObject).ContainsKey("SomeMember")) {
// expandoObject.SomeMember exists.
}
An important distinction needs to be made here.
Most of the answers here are specific to the ExpandoObject which is mentioned in the question. But a common usage (and reason to land on this question when searching) is when using the ASP.Net MVC ViewBag. That's a custom implementation/subclass of DynamicObject, which won't throw an Exception when you check any arbitrary property name for null. Suppose you might declare a property like:
#{
ViewBag.EnableThinger = true;
}
Then suppose you wanted to check its value, and whether it's even set - whether it exists. The following is valid, will compile, won't throw any exceptions, and gives you the right answer:
if (ViewBag.EnableThinger != null && ViewBag.EnableThinger)
{
// Do some stuff when EnableThinger is true
}
Now get rid of the declaration of EnableThinger. Same code compiles and runs properly. No need for reflection.
Unlike ViewBag, ExpandoObject will throw if you check for null on a property that doesn't exist. In order to get MVC ViewBag's gentler functionality out of your dynamic objects, you'll need to use an implementation of dynamic that doesn't throw.
You could simply use the exact implementation in MVC ViewBag:
. . .
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = ViewData[binder.Name];
// since ViewDataDictionary always returns a result even if the key does not exist, always return true
return true;
}
. . .
https://github.com/ASP-NET-MVC/aspnetwebstack/blob/master/src/System.Web.Mvc/DynamicViewDataDictionary.cs
You can see it being tied into MVC Views here, in MVC ViewPage:
http://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/ViewPage.cs
The key to DynamicViewDataDictionary's graceful behavior is the Dictionary implementation on ViewDataDictionary, here:
public object this[string key]
{
get
{
object value;
_innerDictionary.TryGetValue(key, out value);
return value;
}
set { _innerDictionary[key] = value; }
}
https://github.com/ASP-NET-MVC/aspnetwebstack/blob/master/src/System.Web.Mvc/ViewDataDictionary.cs
In other words, it always returns a value for all keys, regardless of what's in it - it simply returns null when nothing's there. But, ViewDataDictionary has the burden of being tied to MVC's Model, so it's better to strip out just the graceful dictionary parts for use outside MVC Views.
It's too long to really post all the guts here - most of it just implementing IDictionary - but here's a dynamic object (class DDict) that doesn't throw for null checks on properties that haven't been declared, on Github:
https://github.com/b9chris/GracefulDynamicDictionary
If you just want to add it to your project via NuGet, its name is GracefulDynamicDictionary.
I wanted to create an extension method so I could do something like:
dynamic myDynamicObject;
myDynamicObject.propertyName = "value";
if (myDynamicObject.HasProperty("propertyName"))
{
//...
}
... but you can't create extensions on ExpandoObject according to the C# 5 documentation (more info here).
So I ended up creating a class helper:
public static class ExpandoObjectHelper
{
public static bool HasProperty(ExpandoObject obj, string propertyName)
{
return obj != null && ((IDictionary<String, object>)obj).ContainsKey(propertyName);
}
}
To use it:
// If the 'MyProperty' property exists...
if (ExpandoObjectHelper.HasProperty(obj, "MyProperty"))
{
...
}
UPDATED: You can use delegates and try to get a value from the dynamic object property if it exists. If there is no property, simply catch the exception and return false.
Take a look, it works fine for me:
class Program
{
static void Main(string[] args)
{
dynamic userDynamic = new JsonUser();
Console.WriteLine(IsPropertyExist(() => userDynamic.first_name));
Console.WriteLine(IsPropertyExist(() => userDynamic.address));
Console.WriteLine(IsPropertyExist(() => userDynamic.last_name));
}
class JsonUser
{
public string first_name { get; set; }
public string address
{
get
{
throw new InvalidOperationException("Cannot read property value");
}
}
}
static bool IsPropertyExist(GetValueDelegate getValueMethod)
{
try
{
//we're not interesting in the return value. What we need to know is whether an exception occurred or not
getValueMethod();
return true;
}
catch (RuntimeBinderException)
{
// RuntimeBinderException occurred during accessing the property
// and it means there is no such property
return false;
}
catch
{
//property exists, but an exception occurred during getting of a value
return true;
}
}
delegate string GetValueDelegate();
}
The output of the code is the following:
True
True
False
I answered a very similar question recently: How do I reflect over the members of dynamic object?
Shortly, ExpandoObject is not the only dynamic object you might get. Reflection would work for static types (types that do not implement IDynamicMetaObjectProvider). For types that do implement this interface, reflection is basically useless. For ExpandoObject, you can simply check whether the property is defined as a key in the underlying dictionary. For other implementations, it might be challenging and sometimes the only way is to work with exceptions. For details, follow the link above.
Why you do not want to use Reflection to get set of type properyes? Like this
dynamic v = new Foo();
Type t = v.GetType();
System.Reflection.PropertyInfo[] pInfo = t.GetProperties();
if (Array.Find<System.Reflection.PropertyInfo>(pInfo, p => { return p.Name == "PropName"; }). GetValue(v, null) != null))
{
//PropName initialized
}
This extension method checks for the existence of a property and then returns the value or null. This is useful if you do not want your applications to throw unnecessary exceptions, at least ones you can help.
public static object Value(this ExpandoObject expando, string name)
{
var expandoDic = (IDictionary<string, object>)expando;
return expandoDic.ContainsKey(name) ? expandoDic[name] : null;
}
If can be used as such :
// lookup is type 'ExpandoObject'
object value = lookup.Value("MyProperty");
or if your local variable is 'dynamic' you will have to cast it to ExpandoObject first.
// lookup is type 'dynamic'
object value = ((ExpandoObject)lookup).Value("PropertyBeingTested");
Depending on your use case, if null can be considered as being the same as undefined, you can turn your ExpandoObject into a DynamicJsonObject.
dynamic x = new System.Web.Helpers.DynamicJsonObject(new ExpandoObject());
x.a = 1;
x.b = 2.50;
Console.WriteLine("a is " + (x.a ?? "undefined"));
Console.WriteLine("b is " + (x.b ?? "undefined"));
Console.WriteLine("c is " + (x.c ?? "undefined"));
Output:
a is 1
b is 2.5
c is undefined
(authorDynamic as ExpandoObject).Any(pair => pair.Key == "YourProp");
Hey guys stop using Reflection for everything it costs a lots of CPU cycles.
Here is the solution:
public class DynamicDictionary : DynamicObject
{
Dictionary<string, object> dictionary = new Dictionary<string, object>();
public int Count
{
get
{
return dictionary.Count;
}
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
string name = binder.Name;
if (!dictionary.TryGetValue(binder.Name, out result))
result = "undefined";
return true;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
dictionary[binder.Name] = value;
return true;
}
}
Try this one
public bool PropertyExist(object obj, string propertyName)
{
return obj.GetType().GetProperty(propertyName) != null;
}

Categories