C#: Printing all properties of an object [duplicate] - c#

This question already has answers here:
What is the best way to dump entire objects to a log in C#?
(16 answers)
Closed 9 years ago.
Is there a method built into .NET that can write all the properties and such of an object to the console?
One could make use of reflection of course, but I'm curious if this already exists...especially since you can do it in Visual Studio in the Immediate Window. There you can type an object name (while in debug mode), press enter, and it is printed fairly prettily with all its stuff.
Does a method like this exist?

You can use the TypeDescriptor class to do this:
foreach(PropertyDescriptor descriptor in TypeDescriptor.GetProperties(obj))
{
string name = descriptor.Name;
object value = descriptor.GetValue(obj);
Console.WriteLine("{0}={1}", name, value);
}
TypeDescriptor lives in the System.ComponentModel namespace and is the API that Visual Studio uses to display your object in its property browser. It's ultimately based on reflection (as any solution would be), but it provides a pretty good level of abstraction from the reflection API.

Based on the ObjectDumper of the LINQ samples I created a version that dumps each of the properties on its own line.
This Class Sample
namespace MyNamespace
{
public class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
public Address Address { get; set; }
public IList<Hobby> Hobbies { get; set; }
}
public class Hobby
{
public string Name { get; set; }
}
public class Address
{
public string Street { get; set; }
public int ZipCode { get; set; }
public string City { get; set; }
}
}
has an output of
{MyNamespace.User}
FirstName: "Arnold"
LastName: "Schwarzenegger"
Address: { }
{MyNamespace.Address}
Street: "6834 Hollywood Blvd"
ZipCode: 90028
City: "Hollywood"
Hobbies: ...
{MyNamespace.Hobby}
Name: "body building"
Here is the code.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
public class ObjectDumper
{
private int _level;
private readonly int _indentSize;
private readonly StringBuilder _stringBuilder;
private readonly List<int> _hashListOfFoundElements;
private ObjectDumper(int indentSize)
{
_indentSize = indentSize;
_stringBuilder = new StringBuilder();
_hashListOfFoundElements = new List<int>();
}
public static string Dump(object element)
{
return Dump(element, 2);
}
public static string Dump(object element, int indentSize)
{
var instance = new ObjectDumper(indentSize);
return instance.DumpElement(element);
}
private string DumpElement(object element)
{
if (element == null || element is ValueType || element is string)
{
Write(FormatValue(element));
}
else
{
var objectType = element.GetType();
if (!typeof(IEnumerable).IsAssignableFrom(objectType))
{
Write("{{{0}}}", objectType.FullName);
_hashListOfFoundElements.Add(element.GetHashCode());
_level++;
}
var enumerableElement = element as IEnumerable;
if (enumerableElement != null)
{
foreach (object item in enumerableElement)
{
if (item is IEnumerable && !(item is string))
{
_level++;
DumpElement(item);
_level--;
}
else
{
if (!AlreadyTouched(item))
DumpElement(item);
else
Write("{{{0}}} <-- bidirectional reference found", item.GetType().FullName);
}
}
}
else
{
MemberInfo[] members = element.GetType().GetMembers(BindingFlags.Public | BindingFlags.Instance);
foreach (var memberInfo in members)
{
var fieldInfo = memberInfo as FieldInfo;
var propertyInfo = memberInfo as PropertyInfo;
if (fieldInfo == null && propertyInfo == null)
continue;
var type = fieldInfo != null ? fieldInfo.FieldType : propertyInfo.PropertyType;
object value = fieldInfo != null
? fieldInfo.GetValue(element)
: propertyInfo.GetValue(element, null);
if (type.IsValueType || type == typeof(string))
{
Write("{0}: {1}", memberInfo.Name, FormatValue(value));
}
else
{
var isEnumerable = typeof(IEnumerable).IsAssignableFrom(type);
Write("{0}: {1}", memberInfo.Name, isEnumerable ? "..." : "{ }");
var alreadyTouched = !isEnumerable && AlreadyTouched(value);
_level++;
if (!alreadyTouched)
DumpElement(value);
else
Write("{{{0}}} <-- bidirectional reference found", value.GetType().FullName);
_level--;
}
}
}
if (!typeof(IEnumerable).IsAssignableFrom(objectType))
{
_level--;
}
}
return _stringBuilder.ToString();
}
private bool AlreadyTouched(object value)
{
if (value == null)
return false;
var hash = value.GetHashCode();
for (var i = 0; i < _hashListOfFoundElements.Count; i++)
{
if (_hashListOfFoundElements[i] == hash)
return true;
}
return false;
}
private void Write(string value, params object[] args)
{
var space = new string(' ', _level * _indentSize);
if (args != null)
value = string.Format(value, args);
_stringBuilder.AppendLine(space + value);
}
private string FormatValue(object o)
{
if (o == null)
return ("null");
if (o is DateTime)
return (((DateTime)o).ToShortDateString());
if (o is string)
return string.Format("\"{0}\"", o);
if (o is char && (char)o == '\0')
return string.Empty;
if (o is ValueType)
return (o.ToString());
if (o is IEnumerable)
return ("...");
return ("{ }");
}
}
and you can use it like that:
var dump = ObjectDumper.Dump(user);
Edit
Bi - directional references are now stopped. Therefore the HashCode of an object is stored in a list.
AlreadyTouched fixed (see comments)
FormatValue fixed (see comments)

The ObjectDumper class has been known to do that. I've never confirmed, but I've always suspected that the immediate window uses that.
EDIT: I just realized, that the code for ObjectDumper is actually on your machine. Go to:
C:/Program Files/Microsoft Visual Studio 9.0/Samples/1033/CSharpSamples.zip
This will unzip to a folder called LinqSamples. In there, there's a project called ObjectDumper. Use that.

Maybe via JavaScriptSerializer.Serialize?

Following snippet will do the desired function:
Type t = obj.GetType(); // Where obj is object whose properties you need.
PropertyInfo [] pi = t.GetProperties();
foreach (PropertyInfo p in pi)
{
System.Console.WriteLine(p.Name + " : " + p.GetValue(obj));
}
I think if you write this as extension method you could use it on all type of objects.

Regarding TypeDescriptor from Sean's reply (I can't comment because I have a bad reputation)... one advantage to using TypeDescriptor over GetProperties() is that TypeDescriptor has a mechanism for dynamically attaching properties to objects at runtime and normal reflection will miss these.
For example, when working with PowerShell's PSObject, which can have properties and methods added at runtime, they implemented a custom TypeDescriptor which merges these members in with the standard member set. By using TypeDescriptor, your code doesn't need to be aware of that fact.
Components, controls, and I think maybe DataSets also make use of this API.

This is exactly what reflection is for. I don't think there's a simpler solution, but reflection isn't that code intensive anyway.

Any other solution/library is in the end going to use reflection to introspect the type...

Don't think so. I've always had to write them or use someone else's work to get that info. Has to be reflection as far as i'm aware.
EDIT:
Check this out. I was investigating some debugging on long object graphs and noticed this when i Add Watches, VS throws in this class: Mscorlib_CollectionDebugView<>. It's an internal type for displaying collections nicely for viewing in the watch windows/code debug modes. Now coz it's internal you can reference it, but u can use Reflector to copy (from mscorlib) the code and have your own (the link above has a copy/paste example). Looks really useful.

Related

How do I get the name of a field from within a method using reflection?

I'm experimenting with reflection in c# for the first time (for use in a dev tool I'm building) and I was wondering if someone could help me to access the thing that I'm trying to access?
The code below is the class I'm accessing:
[Serializable]
public class MaterialVariantTarget : BaseNode, IMaterialTarget
{
public MeshRenderer m_Target;
public void ApplyValue(Material value) => m_Target.material = value;
}
The question I want to answer is what is the name of the value that ApplyValue() operate on. So in this example it would be MeshRenderer.material
I've broken the problem down into two parts. Accessing m_Target's Type (MeshRenderer) and the .material property.
The first, I've managed to access:
private Type GetTargetComponentType(Type targetNodeType)
{
foreach (var fieldInfo in targetNodeType.GetFields())
{
if (fieldInfo.Name == "m_Target")
{
var type = fieldInfo.FieldType;
return type;
}
}
return null;
}
I'm finding accessing the scond part more tricky. Is what I'm trying to do even possible and if so, how can I do it?
Many Thanks
[UPDATE]
So the consensus seems to be that I can't access the contents of the method.
I'm going to have to just resort to writing out the info I need as a string hich can then be read but its not ideal :(
Might I have more options if I were to arrange it as a property get/setter? like this:
[Serializable]
public class MaterialVariantTarget : BaseNode, IMaterialTarget
{
public MeshRenderer m_Target;
private Material m_valueProperty
{
get => m_Target.material;
set => m_Target.material = value;
}
public void ApplyValue(Material value) => m_valueProperty = value;
}
Here's two handy extensions I made to retrieve the value of a field or property of an object based on a name or a type:
public static class Extensions
{
public static object GetPropertyOrFieldByName(this object obj, string nameToSearch)
{
foreach (var field in obj.GetType().GetFields())
{
if (field.Name == nameToSearch)
{
return field.GetValue(obj);
}
}
foreach (var property in obj.GetType().GetProperties())
{
if (property.Name == nameToSearch)
{
return property.GetValue(obj);
}
}
return null;
}
public static T GetPropertyOrFieldByType<T>(this object obj) where T : Object
{
foreach (var field in obj.GetType().GetFields())
{
if (field.FieldType == typeof(T))
{
return (T)field.GetValue(obj);
}
}
foreach (var property in obj.GetType().GetProperties())
{
if (property.PropertyType == typeof(T))
{
return (T)property.GetValue(obj);
}
}
return null;
}
}
The usage you require could be implemented this way:
object target = yourMaterialVariantTarget.GetPropertyOrFieldByName("m_Target");
Material material = target.GetPropertyOrFieldByType<Material>();
material.color = Color.red;

C# How to search property name recursively

I need help to solve a problem, my problem is as follows, I have the following object
public class Teste
{
public string Descricao { get; set; }
public Time Time { get; set; }
}
.
public class Time
{
public string Nome { get; set; }
public Time (string nome)
{
Nome = nome;
}
}
I would like to be able to obtain the complete path of a certain property.
var teste = new Teste();
teste.Descricao = "bar";
teste.Time = new Time("foo");
var b = GetProperties(teste, "Nome");
//expected return: "Time.Nome"
I was testing something I arrived at the following method
public static IEnumerable<Tuple<string, string>> GetProperties(object obj, string propertyPath)
{
var objType = obj.GetType();
if (objType.IsValueType || objType.Equals(typeof(string)))
return Enumerable.Repeat(Tuple.Create(propertyPath, obj.ToString()), 1);
else
{
if (obj == null)
return Enumerable.Repeat(Tuple.Create(propertyPath, string.Empty), 1);
else
{
return from prop in objType.GetProperties()
where prop.CanRead && !prop.GetIndexParameters().Any()
let propValue = prop.GetValue(obj, null)
let propType = prop.PropertyType
from nameValPair in GetProperties(propValue, string.Format("{0}.{1}", propertyPath, prop.Name))
select nameValPair;
}
}
}
but it returns everything to me and I would like it to return a specific property.
I think there are some issues with searching properties that come from system modules. You have to decide which properties are worth recursively descending and which ones are not. Also, you'll have to maintain a list of objects that you have already visited to ensure that you do not follow cycles. I think a breadth-first search would be best, but for this example, I'll code a depth-first search. Also, I just return the first match, not all matches, you can adjust as needed. Furthermore, it returns a (mostly useless) string version of the path rather than a list of reflected properties that would be needed to actually access it (You'd have to do reflection again to locate the properties by name to retrieve the value from this "path" string.)
I'll start you off with a basic implementation. Likely someone else can improve upon it.
static string GetPropertyPath(object obj, string name, List<object> visited = null)
{
// does the object have the property?
Type t = obj.GetType();
var properties = t.GetProperties();
foreach (var property in properties) {
if (property.Name == name) {
// that's it!
return name;
}
}
// if we get here, it's because we didn't find the property.
if (visited == null) {
visited = new List<object>();
visited.Add(obj);
}
// Get all the properties of the first object and keep searching,
// keeping track of objects we've visited already.
foreach (var property in properties) {
// Limit which kinds of properties we search
if (object.ReferenceEquals(typeof(Program).Module, property.Module)) {
// get the value of the property
object obj2 = property.GetValue(obj);
// Do not search any previously visited objects
if (!visited.Any(o => object.ReferenceEquals(o, obj2))) {
visited.Add(obj2);
string path = GetPropertyPath(obj2, name, visited);
if (path != null) {
// found it!
return property.Name + "." + path;
}
}
}
}
return null;
}
Example
static void Main(string[] args)
{
var teste = new Teste();
teste.Descricao = "bar";
teste.Time = new Time("foo");
var b = GetPropertyPath(teste, "Nome"); // "Time.Nome"
}

How to use property in dynamic class if i know the name of it [duplicate]

I am trying implement the Data transformation using Reflection1 example in my code.
The GetSourceValue function has a switch comparing various types, but I want to remove these types and properties and have GetSourceValue get the value of the property using only a single string as the parameter. I want to pass a class and property in the string and resolve the value of the property.
Is this possible?
1 Web Archive version of original blog post
public static object GetPropValue(object src, string propName)
{
return src.GetType().GetProperty(propName).GetValue(src, null);
}
Of course, you will want to add validation and whatnot, but that is the gist of it.
How about something like this:
public static Object GetPropValue(this Object obj, String name) {
foreach (String part in name.Split('.')) {
if (obj == null) { return null; }
Type type = obj.GetType();
PropertyInfo info = type.GetProperty(part);
if (info == null) { return null; }
obj = info.GetValue(obj, null);
}
return obj;
}
public static T GetPropValue<T>(this Object obj, String name) {
Object retval = GetPropValue(obj, name);
if (retval == null) { return default(T); }
// throws InvalidCastException if types are incompatible
return (T) retval;
}
This will allow you to descend into properties using a single string, like this:
DateTime now = DateTime.Now;
int min = GetPropValue<int>(now, "TimeOfDay.Minutes");
int hrs = now.GetPropValue<int>("TimeOfDay.Hours");
You can either use these methods as static methods or extensions.
Add to any Class:
public class Foo
{
public object this[string propertyName]
{
get { return this.GetType().GetProperty(propertyName).GetValue(this, null); }
set { this.GetType().GetProperty(propertyName).SetValue(this, value, null); }
}
public string Bar { get; set; }
}
Then, you can use as:
Foo f = new Foo();
// Set
f["Bar"] = "asdf";
// Get
string s = (string)f["Bar"];
What about using the CallByName of the Microsoft.VisualBasic namespace (Microsoft.VisualBasic.dll)? It uses reflection to get properties, fields, and methods of normal objects, COM objects, and even dynamic objects.
using Microsoft.VisualBasic;
using Microsoft.VisualBasic.CompilerServices;
and then
Versioned.CallByName(this, "method/function/prop name", CallType.Get).ToString();
Great answer by jheddings. I would like to improve it by allowing referencing of aggregated arrays or collections of objects, so that propertyName could be property1.property2[X].property3:
public static object GetPropertyValue(object srcobj, string propertyName)
{
if (srcobj == null)
return null;
object obj = srcobj;
// Split property name to parts (propertyName could be hierarchical, like obj.subobj.subobj.property
string[] propertyNameParts = propertyName.Split('.');
foreach (string propertyNamePart in propertyNameParts)
{
if (obj == null) return null;
// propertyNamePart could contain reference to specific
// element (by index) inside a collection
if (!propertyNamePart.Contains("["))
{
PropertyInfo pi = obj.GetType().GetProperty(propertyNamePart);
if (pi == null) return null;
obj = pi.GetValue(obj, null);
}
else
{ // propertyNamePart is areference to specific element
// (by index) inside a collection
// like AggregatedCollection[123]
// get collection name and element index
int indexStart = propertyNamePart.IndexOf("[")+1;
string collectionPropertyName = propertyNamePart.Substring(0, indexStart-1);
int collectionElementIndex = Int32.Parse(propertyNamePart.Substring(indexStart, propertyNamePart.Length-indexStart-1));
// get collection object
PropertyInfo pi = obj.GetType().GetProperty(collectionPropertyName);
if (pi == null) return null;
object unknownCollection = pi.GetValue(obj, null);
// try to process the collection as array
if (unknownCollection.GetType().IsArray)
{
object[] collectionAsArray = unknownCollection as object[];
obj = collectionAsArray[collectionElementIndex];
}
else
{
// try to process the collection as IList
System.Collections.IList collectionAsList = unknownCollection as System.Collections.IList;
if (collectionAsList != null)
{
obj = collectionAsList[collectionElementIndex];
}
else
{
// ??? Unsupported collection type
}
}
}
}
return obj;
}
If I use the code from Ed S. I get
'ReflectionExtensions.GetProperty(Type, string)' is inaccessible due to its protection level
It seems that GetProperty() is not available in Xamarin.Forms. TargetFrameworkProfile is Profile7 in my Portable Class Library (.NET Framework 4.5, Windows 8, ASP.NET Core 1.0, Xamarin.Android, Xamarin.iOS, Xamarin.iOS Classic).
Now I found a working solution:
using System.Linq;
using System.Reflection;
public static object GetPropValue(object source, string propertyName)
{
var property = source.GetType().GetRuntimeProperties().FirstOrDefault(p => string.Equals(p.Name, propertyName, StringComparison.OrdinalIgnoreCase));
return property?.GetValue(source);
}
Source
About the nested properties discussion, you can avoid all the reflection stuff if you use the DataBinder.Eval Method (Object, String) as below:
var value = DataBinder.Eval(DateTime.Now, "TimeOfDay.Hours");
Of course, you'll need to add a reference to the System.Web assembly, but this probably isn't a big deal.
The method to call has changed in .NET Standard (as of 1.6). Also we can use C# 6's null conditional operator.
using System.Reflection;
public static object GetPropValue(object src, string propName)
{
return src.GetType().GetRuntimeProperty(propName)?.GetValue(src);
}
The below method works perfect for me:
class MyClass {
public string prop1 { set; get; }
public object this[string propertyName]
{
get { return this.GetType().GetProperty(propertyName).GetValue(this, null); }
set { this.GetType().GetProperty(propertyName).SetValue(this, value, null); }
}
}
To get the property value:
MyClass t1 = new MyClass();
...
string value = t1["prop1"].ToString();
To set the property value:
t1["prop1"] = value;
public static List<KeyValuePair<string, string>> GetProperties(object item) //where T : class
{
var result = new List<KeyValuePair<string, string>>();
if (item != null)
{
var type = item.GetType();
var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var pi in properties)
{
var selfValue = type.GetProperty(pi.Name).GetValue(item, null);
if (selfValue != null)
{
result.Add(new KeyValuePair<string, string>(pi.Name, selfValue.ToString()));
}
else
{
result.Add(new KeyValuePair<string, string>(pi.Name, null));
}
}
}
return result;
}
This is a way to get all properties with their values in a List.
Using PropertyInfo of the System.Reflection namespace. Reflection compiles just fine no matter what property we try to access. The error will come up during run-time.
public static object GetObjProperty(object obj, string property)
{
Type t = obj.GetType();
PropertyInfo p = t.GetProperty("Location");
Point location = (Point)p.GetValue(obj, null);
return location;
}
It works fine to get the Location property of an object
Label1.Text = GetObjProperty(button1, "Location").ToString();
We'll get the Location : {X=71,Y=27}
We can also return location.X or location.Y on the same way.
public class YourClass
{
//Add below line in your class
public object this[string propertyName] => GetType().GetProperty(propertyName)?.GetValue(this, null);
public string SampleProperty { get; set; }
}
//And you can get value of any property like this.
var value = YourClass["SampleProperty"];
The following code is a Recursive method for displaying the entire hierarchy of all of the Property Names and Values contained in an object's instance. This method uses a simplified version of AlexD's GetPropertyValue() answer above in this thread. Thanks to this discussion thread, I was able to figure out how to do this!
For example, I use this method to show an explosion or dump of all of the properties in a WebService response by calling the method as follows:
PropertyValues_byRecursion("Response", response, false);
public static object GetPropertyValue(object srcObj, string propertyName)
{
if (srcObj == null)
{
return null;
}
PropertyInfo pi = srcObj.GetType().GetProperty(propertyName.Replace("[]", ""));
if (pi == null)
{
return null;
}
return pi.GetValue(srcObj);
}
public static void PropertyValues_byRecursion(string parentPath, object parentObj, bool showNullValues)
{
/// Processes all of the objects contained in the parent object.
/// If an object has a Property Value, then the value is written to the Console
/// Else if the object is a container, then this method is called recursively
/// using the current path and current object as parameters
// Note: If you do not want to see null values, set showNullValues = false
foreach (PropertyInfo pi in parentObj.GetType().GetTypeInfo().GetProperties())
{
// Build the current object property's namespace path.
// Recursion extends this to be the property's full namespace path.
string currentPath = parentPath + "." + pi.Name;
// Get the selected property's value as an object
object myPropertyValue = GetPropertyValue(parentObj, pi.Name);
if (myPropertyValue == null)
{
// Instance of Property does not exist
if (showNullValues)
{
Console.WriteLine(currentPath + " = null");
// Note: If you are replacing these Console.Write... methods callback methods,
// consider passing DBNull.Value instead of null in any method object parameters.
}
}
else if (myPropertyValue.GetType().IsArray)
{
// myPropertyValue is an object instance of an Array of business objects.
// Initialize an array index variable so we can show NamespacePath[idx] in the results.
int idx = 0;
foreach (object business in (Array)myPropertyValue)
{
if (business == null)
{
// Instance of Property does not exist
// Not sure if this is possible in this context.
if (showNullValues)
{
Console.WriteLine(currentPath + "[" + idx.ToString() + "]" + " = null");
}
}
else if (business.GetType().IsArray)
{
// myPropertyValue[idx] is another Array!
// Let recursion process it.
PropertyValues_byRecursion(currentPath + "[" + idx.ToString() + "]", business, showNullValues);
}
else if (business.GetType().IsSealed)
{
// Display the Full Property Path and its Value
Console.WriteLine(currentPath + "[" + idx.ToString() + "] = " + business.ToString());
}
else
{
// Unsealed Type Properties can contain child objects.
// Recurse into my property value object to process its properties and child objects.
PropertyValues_byRecursion(currentPath + "[" + idx.ToString() + "]", business, showNullValues);
}
idx++;
}
}
else if (myPropertyValue.GetType().IsSealed)
{
// myPropertyValue is a simple value
Console.WriteLine(currentPath + " = " + myPropertyValue.ToString());
}
else
{
// Unsealed Type Properties can contain child objects.
// Recurse into my property value object to process its properties and child objects.
PropertyValues_byRecursion(currentPath, myPropertyValue, showNullValues);
}
}
}
public static TValue GetFieldValue<TValue>(this object instance, string name)
{
var type = instance.GetType();
var field = type.GetFields(BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance).FirstOrDefault(e => typeof(TValue).IsAssignableFrom(e.FieldType) && e.Name == name);
return (TValue)field?.GetValue(instance);
}
public static TValue GetPropertyValue<TValue>(this object instance, string name)
{
var type = instance.GetType();
var field = type.GetProperties(BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance).FirstOrDefault(e => typeof(TValue).IsAssignableFrom(e.PropertyType) && e.Name == name);
return (TValue)field?.GetValue(instance);
}
Dim NewHandle As YourType = CType(Microsoft.VisualBasic.CallByName(ObjectThatContainsYourVariable, "YourVariableName", CallType), YourType)
Here is another way to find a nested property that doesn't require the string to tell you the nesting path. Credit to Ed S. for the single property method.
public static T FindNestedPropertyValue<T, N>(N model, string propName) {
T retVal = default(T);
bool found = false;
PropertyInfo[] properties = typeof(N).GetProperties();
foreach (PropertyInfo property in properties) {
var currentProperty = property.GetValue(model, null);
if (!found) {
try {
retVal = GetPropValue<T>(currentProperty, propName);
found = true;
} catch { }
}
}
if (!found) {
throw new Exception("Unable to find property: " + propName);
}
return retVal;
}
public static T GetPropValue<T>(object srcObject, string propName) {
return (T)srcObject.GetType().GetProperty(propName).GetValue(srcObject, null);
}
You never mention what object you are inspecting, and since you are rejecting ones that reference a given object, I will assume you mean a static one.
using System.Reflection;
public object GetPropValue(string prop)
{
int splitPoint = prop.LastIndexOf('.');
Type type = Assembly.GetEntryAssembly().GetType(prop.Substring(0, splitPoint));
object obj = null;
return type.GetProperty(prop.Substring(splitPoint + 1)).GetValue(obj, null);
}
Note that I marked the object that is being inspected with the local variable obj. null means static, otherwise set it to what you want. Also note that the GetEntryAssembly() is one of a few available methods to get the "running" assembly, you may want to play around with it if you are having a hard time loading the type.
Have a look at the Heleonix.Reflection library. You can get/set/invoke members by paths, or create a getter/setter (lambda compiled into a delegate) which is faster than reflection. For example:
var success = Reflector.Get(DateTime.Now, null, "Date.Year", out int value);
Or create a getter once and cache for reuse (this is more performant but might throw NullReferenceException if an intermediate member is null):
var getter = Reflector.CreateGetter<DateTime, int>("Date.Year", typeof(DateTime));
getter(DateTime.Now);
Or if you want to create a List<Action<object, object>> of different getters, just specify base types for compiled delegates (type conversions will be added into compiled lambdas):
var getter = Reflector.CreateGetter<object, object>("Date.Year", typeof(DateTime));
getter(DateTime.Now);
Although the original question was about how to get the value of the property using only a single string as the parameter, it makes a lot of sense here to use an Expression rather than simply a string to ensure that the caller never uses a hard coded property name. Here is a one line version with usage:
public static class Utils
...
public static TVal GetPropertyValue<T, TVal>(T t, Expression<Func<T, TVal>> x)
=> (TVal)((x.Body as MemberExpression)?.Member as PropertyInfo)!.GetValue(t);
...
var val = Utils.GetPropertyValue(foo, p => p.Bar);
Here is a slightly better version in terms of readability a error handling:
public static TVal GetPropertyValue<T, TVal>(T t, Expression<Func<T, TVal>> x)
{
var m = (x.Body as MemberExpression)?.Member;
var p = m as PropertyInfo;
if (null == p)
throw new ArgumentException($"Unknown property: {typeof(T).Name}.{(m?.Name??"???")}");
return (TVal)p.GetValue(t);
}
In short you pass in a lambda expression reading a property. The body of the lambda - the part on the right of the fat arrow - is a member expression from which you can get the member name and which you can cast to a PropertyInfo, provided the member is actually a Property and not, for instance, a method.
In the short version, the null forgiving operator - the ! in the expression - tells the compiler that the PropertyInfo will not be null. This is a big lie and you will get a NullReferenceException at runtime. The longer version gives you the name of the property if it manages to get it.
PS: Thanks to Oleg G. for the initial version of this code :)
shorter way ....
var a = new Test { Id = 1 , Name = "A" , date = DateTime.Now};
var b = new Test { Id = 1 , Name = "AXXX", date = DateTime.Now };
var compare = string.Join("",a.GetType().GetProperties().Select(x => x.GetValue(a)).ToArray())==
string.Join("",b.GetType().GetProperties().Select(x => x.GetValue(b)).ToArray());
jheddings and AlexD both wrote excellent answers on how to resolve property strings. I'd like to throw mine in the mix, since I wrote a dedicated library exactly for that purpose.
Pather.CSharp's main class is Resolver. Per default it can resolve properties, array and dictionary entries.
So, for example, if you have an object like this
var o = new { Property1 = new { Property2 = "value" } };
and want to get Property2, you can do it like this:
IResolver resolver = new Resolver();
var path = "Property1.Property2";
object result = r.Resolve(o, path);
//=> "value"
This is the most basic example of the paths it can resolve. If you want to see what else it can, or how you can extend it, just head to its Github page.
Here's what I got based on other answers. A little overkill on getting so specific with the error handling.
public static T GetPropertyValue<T>(object sourceInstance, string targetPropertyName, bool throwExceptionIfNotExists = false)
{
string errorMsg = null;
try
{
if (sourceInstance == null || string.IsNullOrWhiteSpace(targetPropertyName))
{
errorMsg = $"Source object is null or property name is null or whitespace. '{targetPropertyName}'";
Log.Warn(errorMsg);
if (throwExceptionIfNotExists)
throw new ArgumentException(errorMsg);
else
return default(T);
}
Type returnType = typeof(T);
Type sourceType = sourceInstance.GetType();
PropertyInfo propertyInfo = sourceType.GetProperty(targetPropertyName, returnType);
if (propertyInfo == null)
{
errorMsg = $"Property name '{targetPropertyName}' of type '{returnType}' not found for source object of type '{sourceType}'";
Log.Warn(errorMsg);
if (throwExceptionIfNotExists)
throw new ArgumentException(errorMsg);
else
return default(T);
}
return (T)propertyInfo.GetValue(sourceInstance, null);
}
catch(Exception ex)
{
errorMsg = $"Problem getting property name '{targetPropertyName}' from source instance.";
Log.Error(errorMsg, ex);
if (throwExceptionIfNotExists)
throw;
}
return default(T);
}
Here is my solution. It works also with COM objects and allows to access collection/array items from COM objects.
public static object GetPropValue(this object obj, string name)
{
foreach (string part in name.Split('.'))
{
if (obj == null) { return null; }
Type type = obj.GetType();
if (type.Name == "__ComObject")
{
if (part.Contains('['))
{
string partWithoundIndex = part;
int index = ParseIndexFromPropertyName(ref partWithoundIndex);
obj = Versioned.CallByName(obj, partWithoundIndex, CallType.Get, index);
}
else
{
obj = Versioned.CallByName(obj, part, CallType.Get);
}
}
else
{
PropertyInfo info = type.GetProperty(part);
if (info == null) { return null; }
obj = info.GetValue(obj, null);
}
}
return obj;
}
private static int ParseIndexFromPropertyName(ref string name)
{
int index = -1;
int s = name.IndexOf('[') + 1;
int e = name.IndexOf(']');
if (e < s)
{
throw new ArgumentException();
}
string tmp = name.Substring(s, e - s);
index = Convert.ToInt32(tmp);
name = name.Substring(0, s - 1);
return index;
}
Whenever you want to loop over all properties in on an object and then use each value of the property must use this piece of code:
foreach (var property in request.GetType().GetProperties())
{
var valueOfProperty = property.GetValue(properties, null);
}

Any easy way to see which IF condition is false?

I'm posting this question to find a simpler way of achieving a result.
We have a big IF statement that checks for NULL or string.empty. Something like this:
if (string.IsNullOrEmpty(Empl.Name) || string.IsNullOrEmpty(Empl.last) ||
string.IsNullOrEmpty(Empl.init) || string.IsNullOrEmpty(Empl.cat1) ||
string.IsNullOrEmpty(Empl.history) || string.IsNullOrEmpty(Empl.cat2) ||
string.IsNullOrEmpty(Empl.year) || string.IsNullOrEmpty(Empl.month) ||
string.IsNullOrEmpty(Empl.retire) || string.IsNullOrEmpty(Empl.spouse) ||
string.IsNullOrEmpty(Empl.children) || string.IsNullOrEmpty(Empl.bday) ||
string.IsNullOrEmpty(Empl.hire)|| string.IsNullOrEmpty(Empl.death) ||
string.IsNullOrEmpty(Empl.JobName) || string.IsNullOrEmpty(Empl.More) ||
string.IsNullOrEmpty(Empl.AndMore))
{
//Display message. Something like "Error: Name and Month is missing"
return;
}
Any solution I've found so far to address this is time-consuming, and would require writing more code.
Is there any way to know which value is string.IsNullOrEmpty without having to change this IF statement too much? Worse-case, I can check every single statement separately, but I would prefer not doing this.
Thanks.
No, there's no "magic" function that will tell you which of a series of expression in an OR statement are true. Also, since you're using the short-circuiting version, the statement will return true after the first true condition, so the remaining expressions are not even evaluated.
However, you could do something like this:
bool[] checks = {
string.IsNullOrEmpty(Empl.Name) , string.IsNullOrEmpty(Empl.last) ,
string.IsNullOrEmpty(Empl.init) , string.IsNullOrEmpty(Empl.cat1) ,
string.IsNullOrEmpty(Empl.history) , string.IsNullOrEmpty(Empl.cat2) ,
string.IsNullOrEmpty(Empl.year) , string.IsNullOrEmpty(Empl.month) ,
string.IsNullOrEmpty(Empl.retire) , string.IsNullOrEmpty(Empl.spouse) ,
string.IsNullOrEmpty(Empl.children) , string.IsNullOrEmpty(Empl.bday) ,
string.IsNullOrEmpty(Empl.hire) , string.IsNullOrEmpty(Empl.death) ,
string.IsNullOrEmpty(Empl.JobName) , string.IsNullOrEmpty(Empl.More) ,
string.IsNullOrEmpty(Empl.AndMore)
};
if(checks.Any())
{
//Display message. Something like "Error: Name and Month is missing"
return;
}
now the checks variable holds the result of each expression.
I find this sort of an more elegant way to use ModelState.isValid.
Some reference: What is ModelState.IsValid valid for in ASP.NET MVC in NerdDinner?
For your model, you can add following annotation:
[Required(AllowEmptyStrings= false)]
public string Boo { get; set; }
When you do validation, try:
if (!ModelState.IsValid)
{
//Display message. Something like "Error: Name and Month is missing"
return;
}
Yes, write your own string extension method that does the same check, but also takes in a List and add the field name to the list. Declare the list of strings before the if and you will have a list of offending fields where your comment is.
This can be improved upon with a bit of reflection to automatically get the name and maybe make a few optimizations but it is on the right track.
Keep in mind that the first condition that violates the if statement will cause it to fail, so you will get an incomplete list (of one item) unless your if is constructed differently.
public static class StringExtensions
{
public static bool CheckIsNullOrEmptyAndListIt(this string field, string fieldName, List<string> naughties)
{
var result = String.IsNullOrEmpty(field);
if (result == true)
{
naughties.Add(fieldName);
}
return result;
}
}
}
using System.IO;
using System;
using System.Linq;
public class Program
{
public class Dog
{
public static string Name {get;set;}
public static string Race {get;set;}
}
public static bool validate(Dog dog)
{
bool val = true;
var y = dog.GetType()
.GetProperties()
.Select(p =>
{
object value =p.GetValue(dog,null);
if(string.IsNullOrEmpty(value.ToString())){ val=false; return false;}
else return true;
})
.ToArray();
return val;
}
public static void Main()
{
Dog dog= new Dog();
Dog.Name = "Peter";
Dog.Race = "";
if(validate(dog))
{
Console.WriteLine("Hello, World!");
}
}
}
You can use something like this :
public static class ValidationHelper
{
public static IEnumerable<string> FindEmptyProperties<T>(T target, params Expression<Func<T, string>>[] propertySelectors)
{
foreach (var propertySelector in propertySelectors)
{
if (string.IsNullOrEmpty(propertySelector.Compile()(target)))
{
var memberExpr = propertySelector.Body as MemberExpression;
yield return memberExpr.Member.Name;
}
}
}
}
Usage :
var failed = ValidationHelper.FindEmptyProperties(Empl, x => x.Name, x => x.last, x => x.init, x => x.cat1).ToList();
if (failed.Any())
{
throw new InvalidOperationException(
string.Format("Error: {0} is missing",
string.Join(", ", failed)));
}
If you use ASP.NET MVC maybe use DataAnnotations...
For the general c# context consider PostSharp aspect oriented library! Geat project!
Otherwise: Maybe a reflection solution using plain .NET ? (Created just for you! I think i keep for some own projects maybe)
Works with different types and you can control the targeted bindingflags.
Provides a common base class for your data transfer objects. (dto)
Reflection is performance optimized and working for generics as well!
public class Program
{
public void Main()
{
Empl test = new Empl()
{
TestProp = "blub",
TestInt = 1
};
if (test.ValidateProperties(Validations.CheckEmptyStringsAndZeroInts))
{
Console.WriteLine("validation passed");
}
else
{
Console.WriteLine("validation failed");
}
}
}
private static class Validations
{
//put this in a static class with standard checks
public static Func<object, bool> CheckEmptyStringsAndZeroInts = o =>
{
if (o is string && string.IsNullOrEmpty((string)o))
{
return false;
}
else if (o is int && ((int) o) == 0)
{
return false;
}
// ignore other property types
return true;
};
}
// Derive all your models like this. deriving from an Empl class is still valid and working!
//[IncludeBindingFlagsForPropertyReflctionAttribute(/*your custom binding flags*/)] //can also override the binding flags in derived classes!
public class Empl : DtoBase<Empl>
{
public string TestProp { get; set; }
public int TestInt { get; set; }
// Your properties here
}
// Helps you to control the targeted properties. you can filter for public or protected members for example
public class IncludeBindingFlagsForPropertyReflctionAttribute : Attribute
{
public BindingFlags BindingFlags { get; }
public IncludeBindingFlagsForPropertyReflctionAttribute(BindingFlags propertySearchBindingFlags)
{
BindingFlags = propertySearchBindingFlags;
}
}
//Looks much. But used once as base class can do those validations for you
[IncludeBindingFlagsForPropertyReflction(BindingFlags.Public | BindingFlags.Instance)]
public abstract class DtoBase<TDto> where TDto : DtoBase<TDto>
{
private static Dictionary<Type, List<PropertyInfo>> DtoPropertyInfosStorage { get; }
private List<PropertyInfo> DtoPropertyInfos => DtoPropertyInfosStorage[typeof (TDto)];
static DtoBase()
{
DtoPropertyInfosStorage = new Dictionary<Type, List<PropertyInfo>>();
Type tDto = typeof (TDto);
var includeBindingFlagsForProperty = GetAttribute(tDto);
BindingFlags defaultTargetFlags = BindingFlags.Instance | BindingFlags.Public;
DtoPropertyInfosStorage.Add(typeof(TDto), new List<PropertyInfo>(typeof(TDto).GetProperties(includeBindingFlagsForProperty?.BindingFlags ?? defaultTargetFlags)));
}
private static IncludeBindingFlagsForPropertyReflctionAttribute GetAttribute(Type dtoType)
{
bool stopRecursion = !dtoType.IsSubclassOf(typeof(DtoBase<TDto>));
var includeBindingFlagsForProperty = dtoType.GetCustomAttributes(typeof(IncludeBindingFlagsForPropertyReflctionAttribute)).FirstOrDefault();
if (includeBindingFlagsForProperty == null && !stopRecursion)
{
return GetAttribute(dtoType.BaseType);
}
return null;
}
/// <summary>
/// You can handle your validation type in you validation function yourself.
/// </summary>
public bool ValidateProperties(Func<object, bool> validationFunction)
{
foreach (KeyValuePair<Type, List<PropertyInfo>> dtoPropertyInfo in DtoPropertyInfosStorage)
{
foreach (PropertyInfo propertyInfo in DtoPropertyInfos)
{
if (!validationFunction(propertyInfo.))
{
return false;
}
}
}
return true;
}
/// <summary>
/// You can pass your targeted property type like string to TPropertyType
/// <![CDATA[ Example:
/// if(ValidateProperties<string>(validate => !string.IsNullOrEmpty(validate)))
/// {
/// properties not empty?
/// }
/// ]]]]>
/// </summary>
public bool ValidateProperties<TPropertyType>(Func<TPropertyType, bool> validationFunction)
{
List<PropertyInfo> targetPropertyInfos =
DtoPropertyInfos.Where(prop => prop.PropertyType == typeof (TPropertyType))
.ToList();
foreach (PropertyInfo dtoPropertyInfo in targetPropertyInfos)
{
if (validationFunction((TPropertyType) dtoPropertyInfo.GetValue(this)))
{
return false;
}
}
return true;
}
}

Getting the DisplayNameAttribute from an Internal class

I have a class that is declared Internal. It is decorated with various annotations. In particular is the [DisplayName("My Display Name")] annotation. I have some code that will retrieve the value but only works if the class is declared public. I am sort of new to using reflection. I believe I need to specify that the BindingFlags.NonPublic be used but I am not sure where.
LinqPAD code:
void Main()
{
List<SpGetProfileInfoResult> p = new List<SpGetProfileInfoResult>();
p.Add(new SpGetProfileInfoResult() { FName = "Eric" });
p.Add(new SpGetProfileInfoResult() { FName = "Mike" });
p.Dump();
foreach (var item in p)
{
Console.WriteLine(item.DisplayName(i => i.FName));
Console.WriteLine(item.FName);
}
}
public partial class SpGetProfileInfoResult
{
// Uncomment this annotation to see that this part will work
// [System.ComponentModel.DisplayNameAttribute("[BILLTO-FNAME]")]
public string FName { get; set; }
}
public partial class SpGetProfileInfoResult
{
internal class Metadata
{
// This attribute is never available seems.
[System.ComponentModel.DisplayNameAttribute("[BILL-FNAME]")]
public string FName { get; set; }
}
}
public static class Tag
{
public static T GetAttribute<T>(this MemberInfo member, bool isRequired) where T : Attribute
{
var attribute = member.GetCustomAttributes(typeof(T), false).SingleOrDefault();
if (attribute == null && isRequired)
{
throw new ArgumentException(
string.Format(
"The {0} attribute must be defined on member {1}",
typeof(T).Name,
member.Name));
}
return (T)attribute;
}
public static string DisplayName<T>(this T src,Expression<Func<T, object>> propertyExpression)
{
Type metadata = null;
var memberInfo = GetPropertyInformation(propertyExpression.Body);
if (memberInfo == null)
{
throw new ArgumentException(
"No property reference expression was found.",
"propertyExpression");
}
var attr = memberInfo.GetAttribute<DisplayNameAttribute>(false);
if (attr == null)
{
return memberInfo.Name;
}
return attr.DisplayName;
}
public static MemberInfo GetPropertyInformation(Expression propertyExpression)
{
MemberExpression memberExpr = propertyExpression as MemberExpression;
if (memberExpr == null)
{
UnaryExpression unaryExpr = propertyExpression as UnaryExpression;
if (unaryExpr != null && unaryExpr.NodeType == ExpressionType.Convert)
{
memberExpr = unaryExpr.Operand as MemberExpression;
}
}
if (memberExpr != null && memberExpr.Member.MemberType == MemberTypes.Property)
{
return memberExpr.Member;
}
return null;
}
}
Usage:
If you don't have LinqPAD, you should download it then you can test this pretty easily by just creating a new C# Program in LinkPAD
Debug.WriteLine(item.DisplayName(i => i.FName));
So it looks like you want to be able to decorate existing members of a partial class, by providing metadata in a separate partial piece. There's no built-in mechanism for that (see eg this question and the classes mentioned in the answer), but if you're willing to stick to a convention, you can roll your own:
So suppose we have
public partial class SpGetProfileInfoResult
{
public string FName { get; set; }
}
in a partial piece we can't change, and
public partial class SpGetProfileInfoResult
{
internal class Metadata
{
[System.ComponentModel.DisplayNameAttribute("[BILL-FNAME]")]
public string FName { get; set; }
}
}
in a partial piece we can change. You already have most of the pieces: in DisplayName(), you successfully determine that we are looking at the FName property; you then look for a DisplayNameAttribute on T.FName, but there isn't one, so that's where it stops.
What you need to do is, in the case where you don't find the attribute you need,
var attr = memberInfo.GetAttribute<DisplayNameAttribute>(false);
if (attr == null)
{
Look for a nested class named Metadata - note here is one place we use BindingFlags.NonPublic
// Try and get a nested metadata class
var metadataType = typeof(T)
.GetNestedType("Metadata",
BindingFlags.Public | BindingFlags.NonPublic);
If we find one:
if (metadataType != null)
{
Look for a member of the same name as was originally being talked about (BindingFlags.NonPublic again)
var membersOnMetadataType = metadataType.GetMember(memberInfo.Name,
BindingFlags.Instance |
BindingFlags.Public |
BindingFlags.NonPublic);
If there is one, use your helper method, but this time pass it the metadata type's member:
if (membersOnMetadataType.Any())
{
var attrOnMetadataType = membersOnMetadataType[0]
.GetAttribute<DisplayNameAttribute>(false);
return attrOnMetadataType.DisplayName;
(I've omitted a final nullity check here, as well as closing the control flow)
Depending on how distasteful you find that "Metadata" string, you could instead do something declarative with attributes:
have a class-level attribute that goes on SpGetProfileInfoResult (the piece you can change) that points at its Metadata using typeof (this is the approach taken by System.ComponentModel), or
have a class-level attribute that goes on Metadata, to have it claim 'I am a metadata type'. Then instead of searching for a nested class named a fixed string, we would instead search for a nested class having this particular attribute.
After working on this for a while I came up with a Hack. I am sure someone out there can help me clean this up a bit, but this is what I found works. I had to add the "Metadata" nested class to the DeclaringType and then do a GetMember on that result, which returns a collection of members.
public static string DisplayName<T>(this T src, Expression<Func<T, object>> propertyExpression)
{
var memberInfo = GetPropertyInformation(propertyExpression.Body);
var mytype = src.GetType();
string strType = mytype.Name + "+Metadata";
var metaType = Type.GetType(strType);
MemberInfo[] mem = metaType.GetMember(memberInfo.Name);
var att = mem[0].GetCustomAttributes(typeof(DisplayNameAttribute), true).FirstOrDefault() as DisplayNameAttribute;
if (att == null)
return memberInfo.Name;
else
return att.DisplayName;
}
I won't try to debug your code because you're using some classes that I'm not familiar with.
One thing I do know is that MemberInfo does not have a GetAttribute() function. You must be using an extension method there.
However I can tell you that you don't need any special bindingflags just because the type is internal. Only the visibility of the member is important, and in this case it's public.
using System;
using System.ComponentModel;
namespace ConsoleApplication1
{
internal class Metadata
{
[DisplayName("[BILL-FNAME]")]
public string FName { get; set; }
}
class Program
{
static void Main()
{
var memberInfo = typeof(Metadata).GetMember("FName")[0];
var atrributes = memberInfo.GetCustomAttributes(false);
Console.WriteLine(atrributes[0].GetType().Name);
}
}
}
Output:
DisplayNameAttribute

Categories