C# reflection get all properties of a type (including inheritance) [duplicate] - c#

I want to dynamically parse an object tree to do some custom validation. The validation is not important as such, but I want to understand the PropertyInfo class better.
I will be doing something like this:
public bool ValidateData(object data)
{
foreach (PropertyInfo propertyInfo in data.GetType().GetProperties())
{
if (the property is a string)
{
string value = propertyInfo.GetValue(data, null);
if value is not OK
{
return false;
}
}
}
return true;
}
Really the only part I care about at the moment is 'if the property is a string'. How can I find out from a PropertyInfo object what type it is?
I will have to deal with basic stuff like strings, ints, doubles. But I will have to also deal with objects too, and if so I will need to traverse the object tree further down inside those objects to validate the basic data inside them, they will also have strings etc.

Use PropertyInfo.PropertyType to get the type of the property.
public bool ValidateData(object data)
{
foreach (PropertyInfo propertyInfo in data.GetType().GetProperties())
{
if (propertyInfo.PropertyType == typeof(string))
{
string value = propertyInfo.GetValue(data, null);
if value is not OK
{
return false;
}
}
}
return true;
}

I just stumbled upon this great post. If you are just checking whether the data is of string type then maybe we can skip the loop and use this struct (in my humble opinion)
public static bool IsStringType(object data)
{
return (data.GetType().GetProperties().Where(x => x.PropertyType == typeof(string)).FirstOrDefault() != null);
}

Related

C# How to turn all empty lists inside object into null

First of all, i'm aware of the popular advice that you should avoid returning empty lists at all. But as of now, due to a myriad of reasons, i'm met with no other choice but to do just that.
What i'm asking is how do I iterate through the properties of an object (probably through Reflection), take whatever lists I may find and check if it's empty. If so, then turn it into null, otherwise, leave it be.
I'm stuck with the following code, which includes somewhat of a try with Reflection:
private static void IfEmptyListThenNull<T>(T myObject)
{
foreach (PropertyInfo propertyInfo in myObject.GetType().GetProperties())
{
if (propertyInfo.PropertyType.IsGenericType && propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(List<>))
{
//How to know if the list i'm checking is empty, and set its value to null
}
}
}
This should work for you, just use GetValue method and cast value to IList, then check for emptiness and set this value via SetValue to null.
private static void IfEmptyListThenNull<T>(T myObject)
{
foreach (PropertyInfo propertyInfo in myObject.GetType().GetProperties())
{
if (propertyInfo.PropertyType.IsGenericType && propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(List<>))
{
if (((IList)propertyInfo.GetValue(myObject, null)).Count == 0)
{
propertyInfo.SetValue(myObject, null);
}
}
}
}

Convert object with list back to a class and find specific data from the object

I would like to create a function allow to get data from any classes with provide a key value, but I am stack when converting object back to the class. The following is my code.
var ListABC = new List<ABC>();
GetData(ListABC, typeof(ABC), "A1");
Here is my Function :-
Public void GetData(object obj, Type objType, string find)
{
// Note! not able to using (List<ABC>)obj, because you never know what tyoe of object will be pass in.
// How to get list data of "A1" after List ABC as a object? assume this function allow any classes.
}
Here is my class :-
public class ABC {
protected int _A1;
protected bool _B1;
protected string _C1;
public int A1
{
get
{
return this._A1;
}
set
{
this._A1 = value;
}
}
public bool B1
{
get
{
return this._B1;
}
set
{
this._B1 = value;
}
}
public string C1
{
get
{
return this._C1;
}
set
{
this._C1 = value;
}
}
}
As Daniel said, make GetData generic:
public void GetData<T>(IList<T> obj, string find)
{
}
and then call it like so:
GetData(ListABC, "A1");
You can even enforce constraints on T, for example:
public void GetData<T>(IList<T> obj, string find)
where T: IConvertible
{
}
If you don't want to implement an interface on the list item objects you will pass here, you could also pass a func:
public void GetData<T>(IList<T> obj, Func<T, string> idFunc, string find)
{
var matchingItems = obj.Where(o => idFunc(o) == find);
}
and call it like so:
GetData(ListABC, i => i.A1, "A1");
Edit: Do you just want ListABC.Select(i => i.A1) ?
If you want minimum change in your code. you can do it like below.
Although, making method generic is good idea, but as you are already passing type of ABC to the method, you are not required to make method generic.
here type you have passed is suggesting which type of data list is holding
Assumptions: you method's return type is void (so assuming you don't want anything to be returned. and also you are passing only one string find as a property to get so at a time you want data of only specified property.
if your requirements are simpler and scope of data is limited in your method only, you can always choose simpler way (which is easily understandable and readable)
try something like below,
public void GetData(object obj, Type objType, string find)
{
//as you are passing type of list here, you can use it.
if(objType == typeof(ABC))
{
List<ABC> list = (List<ABC>)obj;
//now use it.
//here we are getting the property with name as per find (name we passed in method)
PropertyInfo prop = objType.GetProperty(find);
//if there is no property with specified name, PropertyInfo object (prop) will be null
if (prop != null)
{
if (prop.PropertyType == typeof(int))
{
foreach (ABC abcObj in list)
{
object a1Data = prop.GetValue(abcObj);
int data = (int)a1Data;
}
}
}
}
}
Note: drawback of this approach is, you need to handle cases of different Types in this method. So if your method may accept big variety of type, you may not want to go with this idea.

Store type information with DynamicObject

I'm trying to design a process for doing extract transform load operations. I want to use the ExpandoObject in my pipeline to allow me to easily add columns to my data stream. Basically I read data from some kind of datasource cast it a dynamic and yield return it to a pipeline of transforms that add properties to it either based on existing properties or something else then stream it into a database.
The issue I have is that I need type information for all the properties I add to my expando object even if I add a Nullable type. This is lost if the Nullable type is null because of the boxing of the value. I want the type information so that at the end of my pipeline I can implement a datareader over my enumeration of ExpandoObjects and stream the data into a database.
I had hoped the SetMemberBinder.ReturnType property might help me but it seems to return an object.
here's some sample code:
using System;
using System.Collections.Generic;
using System.Dynamic;
using Xunit
namespace Whanger
{
public class MyExpando : DynamicObject
{
Dictionary<string, object> properties = new Dictionary<string, object>();
Dictionary<string, Type> propertyTypes = new Dictionary<string, Type>();
public Dictionary<string, Type> Types
{
get
{
return propertyTypes;
}
}
public Dictionary<string, object> Values
{
get
{
return properties;
}
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (properties.ContainsKey(binder.Name))
{
result = properties[binder.Name];
return true;
}
else
{
result = null;
return false;
}
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
properties[binder.Name] = value;
propertyTypes[binder.Name] = binder.ReturnType;//always object :(
return true;
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
dynamic method = properties[binder.Name];
result = method(args[0].ToString(), args[1].ToString());
return true;
}
}
public class MyExpandoTests
{
[Fact]
public void CanAddDynamicMembers()
{
dynamic obj = new MyExpando();
obj.Name = "Wibble";
obj.Value = 2;
Assert.Equal(obj.Name, "Wibble");
Assert.Equal(obj.Value, 2);
}
[Fact]
public void CanMaintainType()
{
dynamic obj = new MyExpando();
int? nullableInt = null;
obj.NullInt = nullableInt;
obj.Name = "Wibble";
Assert.Equal(obj.Name, "Wibble");
Assert.Null(obj.NullInt);
//fails
Assert.Equal(typeof(int?), ((MyExpando)obj).Types["NullInt"]);
}
}
}
Is there a way to find out the type from TrySetMember? I wonder if there's some way to use some expression tree magic of something?
If anyone has any great ideas I'd love to hear them. It all works well except for the nullable types but they are key for database operations.
Thanks
Yes, it is possible.
I've done some research whether the type information is stored somewhere and I've discovered that during the time of setting the member, there is a Func<System.Runtime.CompilerServices.CallSite,object,int?,object> object being used. This is probably used to store the binding for later uses.
However, this cache is actually passed to the binder: private CallSiteBinder.Cache field. It contains an IDictionary<Type,object> that contains a type of the cache delegate as a key and the delegate itself. So, by examining the generic arguments for the delegate type, you can obtain the type of the expression that was used in the assignment.
Complete method:
private static readonly FieldInfo CallSiteBinder_Cache = typeof(CallSiteBinder).GetField("Cache", BindingFlags.NonPublic | BindingFlags.Instance);
private static Type BindingType(CallSiteBinder binder)
{
IDictionary<Type,object> cache = (IDictionary<Type,object>)CallSiteBinder_Cache.GetValue(binder);
Type ftype = cache.Select(t => t.Key).FirstOrDefault(t => t != null && t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Func<,,,>));
if(ftype == null) return null;
Type[] genargs = ftype.GetGenericArguments();
return genargs[2];
}
This method obtains the secret Cache dictionary and finds a Type key that is has been constructed from Func<T1,T2,T3,TResult>. Then is just extracts the type argument.
Couldn't you add an overload:
public override bool TrySetMember<T>(SetMemberBinder binder, Nullable<T> value)
{
properties[binder.Name] = value;
propertyTypes[binder.Name] = typeof(Nullable<T>);
return true;
}
This is a good question, but there's no general solution. An object parameter can't detect whether the value passed was previously stored in a Nullable<T> variable. It seems like you will have to wait until you have multiple records and see if there are a mix of null and values.
In the specific case here, I would check the ReturnType property on the binder parameter and see if that tells you what you need. I see you already checked that.
Your general problem is that all you have is the value and its type, not the static type of the expression. For example, you can't distinguish these cases either:
string s = "hello";
object o = s;
dynamo.P = s; // case 1
dynamo.P = o; // case 2
or even
dynamo.Use(s);
dynamo.Use(o);
This is very different from statically-typed languages, where the type of an expression is used in overload resolution. It looks like that sort of thing just isn't possible with DynamicObject.

Using PropertyInfo to find out the property type

I want to dynamically parse an object tree to do some custom validation. The validation is not important as such, but I want to understand the PropertyInfo class better.
I will be doing something like this:
public bool ValidateData(object data)
{
foreach (PropertyInfo propertyInfo in data.GetType().GetProperties())
{
if (the property is a string)
{
string value = propertyInfo.GetValue(data, null);
if value is not OK
{
return false;
}
}
}
return true;
}
Really the only part I care about at the moment is 'if the property is a string'. How can I find out from a PropertyInfo object what type it is?
I will have to deal with basic stuff like strings, ints, doubles. But I will have to also deal with objects too, and if so I will need to traverse the object tree further down inside those objects to validate the basic data inside them, they will also have strings etc.
Use PropertyInfo.PropertyType to get the type of the property.
public bool ValidateData(object data)
{
foreach (PropertyInfo propertyInfo in data.GetType().GetProperties())
{
if (propertyInfo.PropertyType == typeof(string))
{
string value = propertyInfo.GetValue(data, null);
if value is not OK
{
return false;
}
}
}
return true;
}
I just stumbled upon this great post. If you are just checking whether the data is of string type then maybe we can skip the loop and use this struct (in my humble opinion)
public static bool IsStringType(object data)
{
return (data.GetType().GetProperties().Where(x => x.PropertyType == typeof(string)).FirstOrDefault() != null);
}

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