I'm looking for a class that can output an object and all its leaf values in a format similar to this:
User
- Name: Gordon
- Age : 60
- WorkAddress
- Street: 10 Downing Street
- Town: London
- Country: UK
- HomeAddresses[0]
...
- HomeAddresses[1]
...
(Or a clearer format). This would be equivalent to:
public class User
{
public string Name { get;set; }
public int Age { get;set; }
public Address WorkAddress { get;set; }
public List<Address> HomeAddresses { get;set; }
}
public class Address
{
public string Street { get;set; }
public string Town { get;set; }
public string Country { get;set; }
}
A kind of string representation of the PropertyGrid control, minus having to implement a large set of designers for each type.
PHP has something that does this called var_dump. I don't want to use a watch, as this is for printing out.
Could anyone point me to something like this if it exists? Or, write one for a bounty.
The object dumper posted in sgmoore's link:
//Copyright (C) Microsoft Corporation. All rights reserved.
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
// See the ReadMe.html for additional information
public class ObjectDumper {
public static void Write(object element)
{
Write(element, 0);
}
public static void Write(object element, int depth)
{
Write(element, depth, Console.Out);
}
public static void Write(object element, int depth, TextWriter log)
{
ObjectDumper dumper = new ObjectDumper(depth);
dumper.writer = log;
dumper.WriteObject(null, element);
}
TextWriter writer;
int pos;
int level;
int depth;
private ObjectDumper(int depth)
{
this.depth = depth;
}
private void Write(string s)
{
if (s != null) {
writer.Write(s);
pos += s.Length;
}
}
private void WriteIndent()
{
for (int i = 0; i < level; i++) writer.Write(" ");
}
private void WriteLine()
{
writer.WriteLine();
pos = 0;
}
private void WriteTab()
{
Write(" ");
while (pos % 8 != 0) Write(" ");
}
private void WriteObject(string prefix, object element)
{
if (element == null || element is ValueType || element is string) {
WriteIndent();
Write(prefix);
WriteValue(element);
WriteLine();
}
else {
IEnumerable enumerableElement = element as IEnumerable;
if (enumerableElement != null) {
foreach (object item in enumerableElement) {
if (item is IEnumerable && !(item is string)) {
WriteIndent();
Write(prefix);
Write("...");
WriteLine();
if (level < depth) {
level++;
WriteObject(prefix, item);
level--;
}
}
else {
WriteObject(prefix, item);
}
}
}
else {
MemberInfo[] members = element.GetType().GetMembers(BindingFlags.Public | BindingFlags.Instance);
WriteIndent();
Write(prefix);
bool propWritten = false;
foreach (MemberInfo m in members) {
FieldInfo f = m as FieldInfo;
PropertyInfo p = m as PropertyInfo;
if (f != null || p != null) {
if (propWritten) {
WriteTab();
}
else {
propWritten = true;
}
Write(m.Name);
Write("=");
Type t = f != null ? f.FieldType : p.PropertyType;
if (t.IsValueType || t == typeof(string)) {
WriteValue(f != null ? f.GetValue(element) : p.GetValue(element, null));
}
else {
if (typeof(IEnumerable).IsAssignableFrom(t)) {
Write("...");
}
else {
Write("{ }");
}
}
}
}
if (propWritten) WriteLine();
if (level < depth) {
foreach (MemberInfo m in members) {
FieldInfo f = m as FieldInfo;
PropertyInfo p = m as PropertyInfo;
if (f != null || p != null) {
Type t = f != null ? f.FieldType : p.PropertyType;
if (!(t.IsValueType || t == typeof(string))) {
object value = f != null ? f.GetValue(element) : p.GetValue(element, null);
if (value != null) {
level++;
WriteObject(m.Name + ": ", value);
level--;
}
}
}
}
}
}
}
}
private void WriteValue(object o)
{
if (o == null) {
Write("null");
}
else if (o is DateTime) {
Write(((DateTime)o).ToShortDateString());
}
else if (o is ValueType || o is string) {
Write(o.ToString());
}
else if (o is IEnumerable) {
Write("...");
}
else {
Write("{ }");
}
}
}
2015 Update
YAML also serves this purpose quite well, this is how it can be done with YamlDotNet
install-package YamlDotNet
private static void DumpAsYaml(object o)
{
var stringBuilder = new StringBuilder();
var serializer = new Serializer();
serializer.Serialize(new IndentedTextWriter(new StringWriter(stringBuilder)), o);
Console.WriteLine(stringBuilder);
}
You could use the JSON serialiser, which should be easy to read for anyone use to working with JSON
User theUser = new User();
theUser.Name = "Joe";
System.Runtime.Serialization.Json.DataContractJsonSerializer serializer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(myPerson.GetType());
MemoryStream ms = new MemoryStream();
serializer.WriteObject(ms, theUser );
string json = Encoding.Default.GetString(ms.ToArray());
Updated 2019
You can find the ObjectDumper project on GitHub. You can also add it via Visual Studio via NuGet package manager.
If you're working with markup, System.Web.ObjectInfo.Print (ASP.NET Web Pages 2) will accomplish this, nicely formatted for HTML.
For example:
#ObjectInfo.Print(new {
Foo = "Hello",
Bar = "World",
Qux = new {
Number = 42,
},
})
In a webpage, produces:
Here's a visual studio extension I wrote to do this:
https://visualstudiogallery.msdn.microsoft.com/c6a21c68-f815-4895-999f-cd0885d8774f
in action:
I know this is an old question, but thought I'd throw out an alternative that worked for me, took me about two minutes to do.
Install Newtonsoft Json.NET:
http://james.newtonking.com/json
(or nuget version) http://www.nuget.org/packages/newtonsoft.json/
Reference Assembly:
using Newtonsoft.Json;
Dump JSON string to log:
txtResult.Text = JsonConvert.SerializeObject(testObj);
You could write that very easily with a little bit of reflection. Something kind of like:
public void Print(object value, int depth)
{
foreach(var property in value.GetType().GetProperties())
{
var subValue = property.GetValue(value);
if(subValue is IEnumerable)
{
PrintArray(property, (IEnumerable)subValue);
}
else
{
PrintProperty(property, subValue);
}
}
}
You can write up the PrintArray and PrintProperty methods.
I have a handy T.Dump() Extension method that should be pretty close to the results you're looking for. As its an extension method, its non-invasive and should work on all POCO objects.
Example Usage
var model = new TestModel();
Console.WriteLine(model.Dump());
Example Output
{
Int: 1,
String: One,
DateTime: 2010-04-11,
Guid: c050437f6fcd46be9b2d0806a0860b3e,
EmptyIntList: [],
IntList:
[
1,
2,
3
],
StringList:
[
one,
two,
three
],
StringIntMap:
{
a: 1,
b: 2,
c: 3
}
}
If you don't feel like copying and pasting Chris S's code, the Visual Studio 2008 samples come with an ObjectDumper.
Drive:\Program Files\Microsoft Visual Studio 9.0\Samples\1033\LinqSamples\ObjectDumper
Here is an alternative:
using System.Reflection;
public void Print(object value)
{
PropertyInfo[] myPropertyInfo;
string temp="Properties of "+value+" are:\n";
myPropertyInfo = value.GetType().GetProperties();
for (int i = 0; i < myPropertyInfo.Length; i++)
{
temp+=myPropertyInfo[i].ToString().PadRight(50)+" = "+myPropertyInfo[i].GetValue(value, null)+"\n";
}
MessageBox.Show(temp);
}
(just touching level 1, no depth, but says a lot)
For most classes, you could use the DataContractSerializer
I just came across a similar requirement in a Blazor project, and came up with the following very simple component to output an object's (and it's child objects') data to the screen:
ObjectDumper.razor:
#using Microsoft.AspNetCore.Components
#using Newtonsoft.Json
<div>
<button onclick="#DumpVMToConsole">#ButtonText</button>
<pre id="json">#_objectAsJson</pre>
</div>
#functions {
// This component allows the easy visualisation of the values currently held in
// an object and its child objects. Add this component to a page and pass in a
// param for the object to monitor, then press the button to see the object's data
// as nicely formatted JSON
// Use like this: <ObjectDumper ObjectToDump="#_billOfLadingVM" />
[Parameter]
private object ObjectToDump { get; set; }
[Parameter]
private string ButtonText { get; set; } = "Show object's data";
string _buttonText;
string _objectAsJson = "";
public void DumpVMToConsole()
{
_objectAsJson = GetObjectAsFormattedJson(ObjectToDump);
Console.WriteLine(_objectAsJson);
}
public string GetObjectAsFormattedJson(object obj)
{
return JsonConvert.SerializeObject(
value: obj,
formatting: Formatting.Indented,
settings: new JsonSerializerSettings
{
PreserveReferencesHandling = PreserveReferencesHandling.Objects
});
}
}
You then stick that somewhere on a Blazor page as follows:
<ObjectDumper ObjectToDump="#YourObjectToVisualise" />
Which then renders a button you can press to see the current values of the bound object:
I've stuck that in a GitHub repo: tomRedox/BlazorObjectDumper
Related
C# 8.0 introduces nullable reference types. Here's a simple class with a nullable property:
public class Foo
{
public String? Bar { get; set; }
}
Is there a way to check a class property uses a nullable reference type via reflection?
In .NET 6, the NullabilityInfoContext APIs were added to handle this. See this answer.
Prior to this, you need to read the attributes yourself. This appears to work, at least on the types I've tested it with.
public static bool IsNullable(PropertyInfo property) =>
IsNullableHelper(property.PropertyType, property.DeclaringType, property.CustomAttributes);
public static bool IsNullable(FieldInfo field) =>
IsNullableHelper(field.FieldType, field.DeclaringType, field.CustomAttributes);
public static bool IsNullable(ParameterInfo parameter) =>
IsNullableHelper(parameter.ParameterType, parameter.Member, parameter.CustomAttributes);
private static bool IsNullableHelper(Type memberType, MemberInfo? declaringType, IEnumerable<CustomAttributeData> customAttributes)
{
if (memberType.IsValueType)
return Nullable.GetUnderlyingType(memberType) != null;
var nullable = customAttributes
.FirstOrDefault(x => x.AttributeType.FullName == "System.Runtime.CompilerServices.NullableAttribute");
if (nullable != null && nullable.ConstructorArguments.Count == 1)
{
var attributeArgument = nullable.ConstructorArguments[0];
if (attributeArgument.ArgumentType == typeof(byte[]))
{
var args = (ReadOnlyCollection<CustomAttributeTypedArgument>)attributeArgument.Value!;
if (args.Count > 0 && args[0].ArgumentType == typeof(byte))
{
return (byte)args[0].Value! == 2;
}
}
else if (attributeArgument.ArgumentType == typeof(byte))
{
return (byte)attributeArgument.Value! == 2;
}
}
for (var type = declaringType; type != null; type = type.DeclaringType)
{
var context = type.CustomAttributes
.FirstOrDefault(x => x.AttributeType.FullName == "System.Runtime.CompilerServices.NullableContextAttribute");
if (context != null &&
context.ConstructorArguments.Count == 1 &&
context.ConstructorArguments[0].ArgumentType == typeof(byte))
{
return (byte)context.ConstructorArguments[0].Value! == 2;
}
}
// Couldn't find a suitable attribute
return false;
}
See this document for details.
The general gist is that either the property itself can have a [Nullable] attribute on it, or if it doesn't the enclosing type might have [NullableContext] attribute. We first look for [Nullable], then if we don't find it we look for [NullableContext] on the enclosing type.
The compiler might embed the attributes into the assembly, and since we might be looking at a type from a different assembly, we need to do a reflection-only load.
[Nullable] might be instantiated with an array, if the property is generic. In this case, the first element represents the actual property (and further elements represent generic arguments). [NullableContext] is always instantiated with a single byte.
A value of 2 means "nullable". 1 means "not nullable", and 0 means "oblivious".
.NET 6 Preview 7 adds reflection APIs to get nullability info.
Libraries: Reflection APIs for nullability information
Obviously, this only helps folks targeting .NET 6+.
Getting top-level nullability information
Imagine you’re implementing a serializer. Using these new APIs the serializer can check whether a given property can be set to null:
private NullabilityInfoContext _nullabilityContext = new NullabilityInfoContext();
private void DeserializePropertyValue(PropertyInfo p, object instance, object? value)
{
if (value is null)
{
var nullabilityInfo = _nullabilityContext.Create(p);
if (nullabilityInfo.WriteState is not NullabilityState.Nullable)
{
throw new MySerializerException($"Property '{p.GetType().Name}.{p.Name}'' cannot be set to null.");
}
}
p.SetValue(instance, value);
}
I wrote a library to do reflection of NRT types - internally it looks at the generated attributes and gives you a simple API:
https://github.com/RicoSuter/Namotion.Reflection
Late answer.
This is what I ended up using thanks to Bill Menees:
static bool IsMarkedAsNullable(PropertyInfo p)
{
return new NullabilityInfoContext().Create(p).WriteState is NullabilityState.Nullable;
}
// Tests:
class Foo
{
public int Int1 { get; set; }
public int? Int2 { get; set; } = null;
public string Str1 { get; set; } = "";
public string? Str2 { get; set; } = null;
public List<Foo> Lst1 { get; set; } = new();
public List<Foo>? Lst2 { get; set; } = null;
public Dictionary<int, object> Dic1 { get; set; } = new();
public Dictionary<int, object>? Dic2 { get; set; } = null;
}
....
var props = typeof(Foo).GetProperties();
foreach(var prop in props)
{
Console.WriteLine($"Prop:{prop.Name} IsNullable:{IsMarkedAsNullable(prop)}");
}
// outputs:
Prop:Int1 IsNullable:False
Prop:Int2 IsNullable:True
Prop:Str1 IsNullable:False
Prop:Str2 IsNullable:True
Prop:Lst1 IsNullable:False
Prop:Lst2 IsNullable:True
Prop:Dic1 IsNullable:False
Prop:Dic2 IsNullable:True
A great answer there by #rico-suter !
The following is for those who just want a quick cut-and-paste solution until the real McCoy is available (see the proposal https://github.com/dotnet/runtime/issues/29723 ).
I put this together based on #canton7's post above plus a short look at the ideas in #rico-suter's code. The change from the #canton7's code is just abstracting the list of attribute sources and including a few new ones.
private static bool IsAttributedAsNonNullable(this PropertyInfo propertyInfo)
{
return IsAttributedAsNonNullable(
new dynamic?[] { propertyInfo },
new dynamic?[] { propertyInfo.DeclaringType, propertyInfo.DeclaringType?.DeclaringType, propertyInfo.DeclaringType?.GetTypeInfo() }
);
}
private static bool IsAttributedAsNonNullable(this ParameterInfo parameterInfo)
{
return IsAttributedAsNonNullable(
new dynamic?[] { parameterInfo },
new dynamic?[] { parameterInfo.Member, parameterInfo.Member.DeclaringType, parameterInfo.Member.DeclaringType?.DeclaringType, parameterInfo.Member.DeclaringType?.GetTypeInfo()
);
}
private static bool IsAttributedAsNonNullable( dynamic?[] nullableAttributeSources, dynamic?[] nullableContextAttributeSources)
{
foreach (dynamic? nullableAttributeSource in nullableAttributeSources) {
if (nullableAttributeSource == null) { continue; }
CustomAttributeData? nullableAttribute = ((IEnumerable<CustomAttributeData>)nullableAttributeSource.CustomAttributes).FirstOrDefault(x => x.AttributeType.FullName == "System.Runtime.CompilerServices.NullableAttribute");
if (nullableAttribute != null && nullableAttribute.ConstructorArguments.Count == 1) {
CustomAttributeTypedArgument attributeArgument = nullableAttribute.ConstructorArguments[0];
if (attributeArgument.ArgumentType == typeof(byte[])) {
var args = (ReadOnlyCollection<CustomAttributeTypedArgument>)(attributeArgument.Value ?? throw new NullReferenceException("Logic error!"));
if (args.Count > 0 && args[0].ArgumentType == typeof(byte)) {
byte value = (byte)(args[0].Value ?? throw new NullabilityLogicException());
return value == 1; // 0 = oblivious, 1 = nonnullable, 2 = nullable
}
} else if (attributeArgument.ArgumentType == typeof(byte)) {
byte value = (byte)(attributeArgument.Value ?? throw new NullReferenceException("Logic error!"));
return value == 1; // 0 = oblivious, 1 = nonnullable, 2 = nullable
} else {
throw new InvalidOperationException($"Unrecognized argument type for NullableAttribute.");
}
}
}
foreach (dynamic? nullableContextAttributeSource in nullableContextAttributeSources) {
if (nullableContextAttributeSource == null) { continue; }
CustomAttributeData? nullableContextAttribute = ((IEnumerable<CustomAttributeData>)nullableContextAttributeSource.CustomAttributes).FirstOrDefault(x => x.AttributeType.FullName == "System.Runtime.CompilerServices.NullableContextAttribute");
if (nullableContextAttribute != null && nullableContextAttribute.ConstructorArguments.Count == 1) {
CustomAttributeTypedArgument attributeArgument = nullableContextAttribute.ConstructorArguments[0];
if (attributeArgument.ArgumentType == typeof(byte)) {
byte value = (byte)(nullableContextAttribute.ConstructorArguments[0].Value ?? throw new NullabilityLogicException());
return value == 1;
} else {
throw new InvalidOperationException($"Unrecognized argument type for NullableContextAttribute.");
}
}
}
return false;
}
It's only the string? which gets a bit tricky. The rest of the nullable types are pretty straightforward to find out. For strings I used the following method, which you need to pass in a PropertyInfo object taken via reflection.
private bool IsNullable(PropertyInfo prop)
{
return prop.CustomAttributes.Any(x => x.AttributeType.Name == "NullableAttribute");
}
I have two classes A and B which have some properties that are the same. I am looking for a way to compare only the same properties and was hoping if there was some nuget package that did this for any type of class.
I don't know how to go about looking for such a nuget package, I already tried using if statements to compare the same properties, but I have a lot of cases like this so it would be easier to use a nuget package to do it.
Also, it is not possible to include inheritance here, as the two classes are not logically linked.
class A {
string title;
DateTime publishDate;
string Author;
int numberOfSales;
}
class B {
DateTime publishDate;
int numberOfSales;
}
I have already did something like this to compare the two same properties
if (A.publishDate.Equals(B.publishDate)) {
// Do something
}
if (A.numberOfSales == B.numberOfSales) {
// Do something
}
I would really be grateful if someone could let me know if there is some nuget package that would just compare the same properties of the two classes.
Why you don't use native interface in c# ?
you can use Icomprable interface like this :
public class A:IComparable<B>
{
public string title;
public DateTime publishDate;
public string Author;
public int numberOfSales;
public int CompareTo(B other)
{
if (this.numberOfSales == other.numberOfSales && this.publishDate.Equals(other.publishDate))
return 0;
if (this.numberOfSales != other.numberOfSales && this.publishDate.Equals(other.publishDate))
return 1;
if (this.numberOfSales == other.numberOfSales && !this.publishDate.Equals(other.publishDate))
return 2;
return -1;
}
}
public class B
{
public DateTime publishDate;
public int numberOfSales;
}
then you can use it like this :
switch (aClass.CompareTo(bClass))
{
case 0:Console.WriteLine("both properties are equal");break;
case 1:Console.WriteLine("PublishDate only equal"); break;
case 2: Console.WriteLine("NumberOfSales only equal"); break;
case -1: Console.WriteLine("None are equal"); break;
}
I hope it will be useful
Just use Reflection.
For example, this class will all fields (because your sample class listings have no Properties, they only have Fields) and return a list of them:
using System;
using System.Linq;
using System.Collections.Generic;
using System.Reflection;
public static class Comparer {
public static List<String> Compare<T1, T2>(T1 a, T2 b) {
var result = new List<String>(); // you can choose to return FieldInfo or values or whatever...
// you can also use .GetProperties() if you actually want Properties with getters.
var aFields = typeof(T1).GetFields(BindingFlags.Instance | BindingFlags.Public);
var bFields = typeof(T2).GetFields(BindingFlags.Instance | BindingFlags.Public);
var aCommonFields = new List<FieldInfo>();
var bCommonFields = new List<FieldInfo>();
Func<IEnumerable<FieldInfo>, FieldInfo, bool> predicate = (other, x) => other.FirstOrDefault(z => z.Name == x.Name && z.FieldType == x.FieldType) != null;
aCommonFields.AddRange(aFields.Where(x => predicate(bFields, x)));
bCommonFields.AddRange(bFields.Where(x => predicate(aCommonFields, x)));
foreach(var aCommonField in aCommonFields) {
var bCommonField = bCommonFields.First(bField => predicate(new[]{ aCommonField }, bField));
var aValue = aCommonField.GetValue(a);
var bValue = bCommonField.GetValue(b);
if (aValue.Equals(bValue)) {
result.Add(aCommonField.Name);
}
}
return result;
}
}
Sample usage:
var a1 = new A { numberOfSales = 42 };
var b2 = new B { numberOfSales = 42 };
var commons = Comparer.Compare(a1, b2);
foreach(var common in commons) {
if (common == nameof(A.numberOfSales)) {
Console.WriteLine("Number of sales match!");
}
}
I like a more controlled way better where you just type the compaire properties as you did in your sample, perhaps use an icomparable interface.
he reflection option that is offered and will be offered is slow, could give null pointer exceptions etc but write once work always, it's not a nuget package but here you go.
public static List<PropertyInfo> GetDifferences(object test1, object test2)
{
if (test1 is null)
throw new ArgumentNullException(nameof(test1));
if (test2 is null)
throw new ArgumentNullException(nameof(test2));
List<PropertyInfo> differences = new List<PropertyInfo>();
foreach (PropertyInfo property in test1.GetType().GetProperties())
{
if (test2.GetType().GetProperties().Any(a => a.Name.Equals(property.Name, StringComparison.Ordinal)))
{
object value1 = property.GetValue(test1, null);
object value2 = property.GetValue(test2, null);
if ((value1 == null) || !value1.Equals(value2))
{
differences.Add(property);
}
}
}
return differences;
}
It will return the properties that both have and are not the same.
I have a class named Configurationwhich inherits from DynamicObject. It it a Dictionary<string, object>. In the constructor, it reads a text file and loads all the values from it splitted by =, so you can create dynamic configuration objects like this:
dynamic configuration = new Configuration("some_file.ini");
Here is my full class:
public sealed class Configuration : DynamicObject
{
private string Path { get; set; }
private Dictionary<string, object> Dictionary { get; set; }
public Configuration(string fileName)
{
this.Path = fileName;
this.Dictionary = new Dictionary<string, object>();
this.Populate();
}
~Configuration()
{
if (this.Dictionary != null)
{
this.Dictionary.Clear();
}
}
private void Populate()
{
using (StreamReader reader = new StreamReader(this.Path))
{
string line;
string currentSection = string.Empty;
while ((line = reader.ReadLine()) != null)
{
if (string.IsNullOrWhiteSpace(line))
{
continue;
}
if (line.StartsWith("[") && line.EndsWith("]"))
{
currentSection = line.Trim('[', ']');
}
else if (line.Contains("="))
{
this.Dictionary.Add(string.Format("{0}{1}{2}",
currentSection,
(currentSection != string.Empty) ? "_" : string.Empty,
line.Split('=')[0].Trim()),
ParseValue(line.Split('=')[1].Trim().Split(';')[0]));
}
}
}
}
private object ParseValue(string value)
{
if (string.IsNullOrWhiteSpace(value))
return string.Empty;
if (value.StartsWith("\"") && value.EndsWith("\""))
return value.Substring(1, value.Length - 1);
if (IsNumeric(value))
return Convert.ToInt32(value);
// TODO: FIXME Floating values (not to be confuse with IPAddress).
//if (IsFloating(value))
// return Convert.ToDouble(value);
if (string.Compare(value, "true", StringComparison.OrdinalIgnoreCase) == 0)
return true;
if (string.Compare(value, "false", StringComparison.OrdinalIgnoreCase) == 0)
return false;
return value;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (this.Dictionary.ContainsKey(binder.Name))
{
if (this.Dictionary[binder.Name] == null)
{
result = null;
}
else
{
result = this.Dictionary[binder.Name];
}
return true;
}
throw new ConfigurationException(binder.Name);
}
public override string ToString()
{
string result = this.Path + " [ ";
int processed = 0;
foreach (KeyValuePair<string, object> value in this.Dictionary)
{
result += value.Key;
processed++;
if (processed < this.Dictionary.Count)
{
result += ", ";
}
}
result += " ]";
return result;
}
private static bool IsNumeric(string value)
{
foreach (char c in value)
if (!char.IsDigit(c))
return false;
return true;
}
private static bool IsFloating(string value)
{
foreach (char c in value)
if (!char.IsDigit(c) && c != '.')
return false;
return true;
}
private class NullObject { }
}
Everything is working flawlessly. I've overriden TryGetMember and I'm returning the object based on the GetMemberBinder Name property. However, I'm facing a problem.
When I execute the following code:
string s = "some_config_key";
string d = configuration.s;
It retrieves the value of the key s rather than some_config_key, meaning that it doesn't evalute the value of the variable s. Is there a workaround for this?
Thanks.
C# dynamic features are partially compiled like the property/method access. To understand this lets take an example.
dynamic myVar = new { a=1, b="test" };
myVar.a += 1;
Here the C# type system would not test for the validity of the property while compilation, only at runtime the code is executed and if the property is not found it will through you runtime error.
So in your code the property access is already complied to access the property named "s" on the dynamic object "configuration".
In C# no-way you can do this not even in dynamically typed languages like python or javascript.
You have to use like this.
dynamic configuration = getConfig("path/to/file");
var myobj = configuration as IDictionary<string,object>;
string s = "config_key";
var value = myobj[s]; // this is correct.
I'm looking to take an in-memory object (or JSON serialization of an object) and emit C# code to produce an equivalent object.
This would be useful for pulling known-good examples from a repository to use as starting points in unit tests. We have considered deserializing JSON, but C# code would have an edge when it comes to refactoring.
There is an interesting Visual Studio extension that addresses this; the Object Exporter. It allows serialization of an in-memory object into C# Object initialization code, JSON and XML. I haven't tried it yet but looks intriguing; will update after trying it out.
If your model is simple, you could use reflection and a string builder to output C# directly. I've done this to populate unit test data exactly as you discussed.
The code sample below was written in a few minutes and generated an object initializer that needed some hand tweaking. A more robust / less buggy function could be written if you plan on doing this a lot.
The second function is recursive, iterating over any Lists within the object, and generating code for those as well.
Disclaimer: This worked for my simple model with basic data types. It generated code that needed cleanup but allowed me to move on quickly. It is only here to serve as an example of how this could be done. Hopefully, it inspires someone to write their own.
In my case, I had an instance of this large dataset (results) that was loaded from the database. In order to remove the database dependency from my unit test, I handed the object to this function which spits out the code that allowed me to mock the object in my test class.
private void WriteInstanciationCodeFromObject(IList results)
{
//declare the object that will eventually house C# initialization code for this class
var testMockObject = new System.Text.StringBuilder();
//start building code for this object
ConstructAndFillProperties(testMockObject, results);
var codeOutput = testMockObject.ToString();
}
private void ConstructAndFillProperties(StringBuilder testMockObject, IList results)
{
testMockObject.AppendLine("var testMock = new " + results.GetType().ToString() + "();");
foreach (object obj in results)
{
//if this object is a list, write code for its contents
if (obj.GetType().GetInterfaces().Contains(typeof(IList)))
{
ConstructAndFillProperties(testMockObject, (IList)obj);
}
testMockObject.AppendLine("testMock.Add(new " + obj.GetType().Name + "() {");
foreach (var property in obj.GetType().GetProperties())
{
//if this property is a list, write code for its contents
if (property.PropertyType.GetInterfaces().Contains(typeof(IList)))
{
ConstructAndFillProperties(testMockObject, (IList)property.GetValue(obj, null));
}
testMockObject.AppendLine(property.Name + " = (" + property.PropertyType + ")\"" + property.GetValue(obj, null) + "\",");
}
testMockObject.AppendLine("});");
}
}
It's possible the object will have a TypeConverter that supports conversion to InstanceDescriptor, which is what the WinForms designer uses when emitting C# code to generate an object. If it can't convert to an InstanceDescriptor, it will attempt to use a parameterless constructor and simply set public properties. The InstanceDescriptor mechanism is handy, since it allows you to specify various construction options such as constructors with parameters or even static factory method calls.
I have some utility code I've written that emits loading of an in-memory object using IL, which basically follows the above pattern (use InstanceDescriptor if possible and, if not, simply write public properties.) Note that this will only produce an equivalent object if the InstanceDescriptor is properly implemented or setting public properties is sufficient to restore object state. If you're emitting IL, you can also cheat and read/write field values directly (this is what the DataContractSerializer supports), but there are a lot of nasty corner cases to consider.
I'm a novice at this as well, but I also needed to take a C# object that defined a hierarchy and extract it to an object initializer to ease setting up a unit test. I borrowed heavily from the above and wound up with this. I'd like to improve the way it handles recognizing user classes.
http://github.com/jefflomax/csharp-object-to-object-literal/blob/master/Program.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ObjectInitializer
{
public class Program
{
public enum Color { Red, Green, Blue, Yellow, Fidget } ;
public class Foo
{
public int FooId { get; set; }
public string FooName { get; set; }
}
public class Thing
{
public int ThingId { get; set; }
public string ThingName { get; set; }
public List<Foo> Foos { get; set; }
}
public class Widget
{
public long Sort { get; set; }
public char FirstLetter { get; set; }
}
public class TestMe
{
public Color Color { get; set; }
public long Key { get; set; }
public string Name { get; set; }
public DateTime Created { get; set; }
public DateTime? NCreated { get; set; }
public bool Deleted { get; set; }
public bool? NDeleted { get; set; }
public double Amount { get; set; }
public Thing MyThing { get; set; }
public List<Thing> Things { get; set; }
public List<Widget> Widgets { get; set; }
}
static void Main(string[] args)
{
var testMe = new TestMe
{
Color = Program.Color.Blue,
Key = 3,
Name = "SAK",
Created = new DateTime(2013,10,20,8,0,0),
NCreated = (DateTime?)null,
Deleted = false,
NDeleted = null,
Amount = 13.1313,
MyThing = new Thing(){ThingId=1,ThingName="Thing 1"},
Things = new List<Thing>
{
new Thing
{
ThingId=4,
ThingName="Thing 4",
Foos = new List<Foo>
{
new Foo{FooId=1, FooName="Foo 1"},
new Foo{FooId=2,FooName="Foo2"}
}
},
new Thing
{
ThingId=5,
ThingName="Thing 5",
Foos = new List<Foo>()
}
},
Widgets = new List<Widget>()
};
var objectInitializer = ToObjectInitializer(testMe);
Console.WriteLine(objectInitializer);
// This is the returned C# Object Initializer
var x = new TestMe { Color = Program.Color.Blue, Key = 3, Name = "SAK", Created = new DateTime(2013, 10, 20, 8, 0, 0), NCreated = null, Deleted = false, NDeleted = null, Amount = 13.1313, MyThing = new Thing { ThingId = 1, ThingName = "Thing 1", Foos = new List<Foo>() }, Things = new List<Thing> { new Thing { ThingId = 4, ThingName = "Thing 4", Foos = new List<Foo> { new Foo { FooId = 1, FooName = "Foo 1" }, new Foo { FooId = 2, FooName = "Foo2" } } }, new Thing { ThingId = 5, ThingName = "Thing 5", Foos = new List<Foo>() } }, Widgets = new List<Widget>() };
Console.WriteLine("");
}
public static string ToObjectInitializer(Object obj)
{
var sb = new StringBuilder(1024);
sb.Append("var x = ");
sb = WalkObject(obj, sb);
sb.Append(";");
return sb.ToString();
}
private static StringBuilder WalkObject(Object obj, StringBuilder sb)
{
var properties = obj.GetType().GetProperties();
var type = obj.GetType();
var typeName = type.Name;
sb.Append("new " + type.Name + " {");
bool appendComma = false;
DateTime workDt;
foreach (var property in properties)
{
if (appendComma) sb.Append(", ");
appendComma = true;
var pt = property.PropertyType;
var name = pt.Name;
var isList = property.PropertyType.GetInterfaces().Contains(typeof(IList));
var isClass = property.PropertyType.IsClass;
if (isList)
{
IList list = (IList)property.GetValue(obj, null);
var listTypeName = property.PropertyType.GetGenericArguments()[0].Name;
if (list != null && list.Count > 0)
{
sb.Append(property.Name + " = new List<" + listTypeName + ">{");
sb = WalkList( list, sb );
sb.Append("}");
}
else
{
sb.Append(property.Name + " = new List<" + listTypeName + ">()");
}
}
else if (property.PropertyType.IsEnum)
{
sb.AppendFormat("{0} = {1}", property.Name, property.GetValue(obj));
}
else
{
var value = property.GetValue(obj);
var isNullable = pt.IsGenericType && pt.GetGenericTypeDefinition() == typeof(Nullable<>);
if (isNullable)
{
name = pt.GetGenericArguments()[0].Name;
if (property.GetValue(obj) == null)
{
sb.AppendFormat("{0} = null", property.Name);
continue;
}
}
switch (name)
{
case "Int64":
case "Int32":
case "Int16":
case "Double":
case "Float":
sb.AppendFormat("{0} = {1}", property.Name, value);
break;
case "Boolean":
sb.AppendFormat("{0} = {1}", property.Name, Convert.ToBoolean(value) == true ? "true" : "false");
break;
case "DateTime":
workDt = Convert.ToDateTime(value);
sb.AppendFormat("{0} = new DateTime({1},{2},{3},{4},{5},{6})", property.Name, workDt.Year, workDt.Month, workDt.Day, workDt.Hour, workDt.Minute, workDt.Second);
break;
case "String":
sb.AppendFormat("{0} = \"{1}\"", property.Name, value);
break;
default:
// Handles all user classes, should likely have a better way
// to detect user class
sb.AppendFormat("{0} = ", property.Name);
WalkObject(property.GetValue(obj), sb);
break;
}
}
}
sb.Append("}");
return sb;
}
private static StringBuilder WalkList(IList list, StringBuilder sb)
{
bool appendComma = false;
foreach (object obj in list)
{
if (appendComma) sb.Append(", ");
appendComma = true;
WalkObject(obj, sb);
}
return sb;
}
}
}
I stumbled across this while looking for the same kind of method Matthew described, and was inspired by Evan's answer to write my own extension method. It generates compilable C# code as a string that can be copy/pasted into Visual Studio. I didn't bother with any particular formatting and just output the code on one line and use ReSharper to format it nicely. I've used it with some big DTOs that we were passing around and so far it works like a charm.
Here's the extension method and a couple helper methods:
public static string ToCreationMethod(this object o)
{
return String.Format("var newObject = {0};", o.CreateObject());
}
private static StringBuilder CreateObject(this object o)
{
var builder = new StringBuilder();
builder.AppendFormat("new {0} {{ ", o.GetClassName());
foreach (var property in o.GetType().GetProperties())
{
var value = property.GetValue(o);
if (value != null)
{
builder.AppendFormat("{0} = {1}, ", property.Name, value.GetCSharpString());
}
}
builder.Append("}");
return builder;
}
private static string GetClassName(this object o)
{
var type = o.GetType();
if (type.IsGenericType)
{
var arg = type.GetGenericArguments().First().Name;
return type.Name.Replace("`1", string.Format("<{0}>", arg));
}
return type.Name;
}
The method GetCSharpString contains the logic, and it's open to extension for any particular type. It was enough for me that it handled strings, ints, decimals, dates anything that implements IEnumerable:
private static string GetCSharpString(this object o)
{
if (o is String)
{
return string.Format("\"{0}\"", o);
}
if (o is Int32)
{
return string.Format("{0}", o);
}
if (o is Decimal)
{
return string.Format("{0}m", o);
}
if (o is DateTime)
{
return string.Format("DateTime.Parse(\"{0}\")", o);
}
if (o is IEnumerable)
{
return String.Format("new {0} {{ {1}}}", o.GetClassName(), ((IEnumerable)o).GetItems());
}
return string.Format("{0}", o.CreateObject());
}
private static string GetItems(this IEnumerable items)
{
return items.Cast<object>().Aggregate(string.Empty, (current, item) => current + String.Format("{0}, ", item.GetCSharpString()));
}
I hope someone finds this useful!
It may comes a bit late, but here is my 5cents on that problem.
The mentioned Visual Studio Extension (OmarElabd/ObjectExporter) was a good idea, but I needed to generate C# code from in-memory objects at runtime, during unit test execution. This is what evolved from the original problem: https://www.nuget.org/packages/ObjectDumper.NET/
ObjectDumper.Dump(obj, DumpStyle.CSharp); returns C# initializer code from a variable. Please let me know if you find issues, you might want to report them on github.
There's a solution similar to what Evan proposed, but a bit better suited for my particular task.
After playing a bit with CodeDOM and Reflection it turned out that it would be too complicated in my case.
The object was serialized as XML, so the natural solution was to use XSLT to simply transform it to the object creation expression.
Sure, it covers only certain types of the cases, but maybe will work for someone else.
Here is an update to #revlucio's solution that adds support for booleans and enums.
public static class ObjectInitializationSerializer
{
private static string GetCSharpString(object o)
{
if (o is bool)
{
return $"{o.ToString().ToLower()}";
}
if (o is string)
{
return $"\"{o}\"";
}
if (o is int)
{
return $"{o}";
}
if (o is decimal)
{
return $"{o}m";
}
if (o is DateTime)
{
return $"DateTime.Parse(\"{o}\")";
}
if (o is Enum)
{
return $"{o.GetType().FullName}.{o}";
}
if (o is IEnumerable)
{
return $"new {GetClassName(o)} \r\n{{\r\n{GetItems((IEnumerable)o)}}}";
}
return CreateObject(o).ToString();
}
private static string GetItems(IEnumerable items)
{
return items.Cast<object>().Aggregate(string.Empty, (current, item) => current + $"{GetCSharpString(item)},\r\n");
}
private static StringBuilder CreateObject(object o)
{
var builder = new StringBuilder();
builder.Append($"new {GetClassName(o)} \r\n{{\r\n");
foreach (var property in o.GetType().GetProperties())
{
var value = property.GetValue(o);
if (value != null)
{
builder.Append($"{property.Name} = {GetCSharpString(value)},\r\n");
}
}
builder.Append("}");
return builder;
}
private static string GetClassName(object o)
{
var type = o.GetType();
if (type.IsGenericType)
{
var arg = type.GetGenericArguments().First().Name;
return type.Name.Replace("`1", $"<{arg}>");
}
return type.Name;
}
public static string Serialize(object o)
{
return $"var newObject = {CreateObject(o)};";
}
}
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.