Fetch and print all properties of an object graph as stringReplace all occurrences with the properties of an objectReturn IEnumerable<KeyValuePair> from a private method; use Dictionary or anon. type?Pattern-matching-esque codeImplementation of stackWPF object model control with singleton and static messenger? ConditionalWeakTable?Safely order a list of objects by DateTimeBasic Pong GameTest all properties with single test functionPolymorphic DBConnector class exerciseEnumerate all members and types with specific attributes
Should I tell my insurance company I'm making payments on my new car?
Why is Madam Hooch not a professor?
Fetch and print all properties of an object graph as string
First-year PhD giving a talk among well-established researchers in the field
What are the penalties for overstaying in USA?
Is adding a new player (or players) a DM decision, or a group decision?
Cascading Repair Costs following Blown Head Gasket on a 2004 Subaru Outback
Why is the voltage measurement of this circuit different when the switch is on?
Can ADFS connect to other SSO services?
Distance Matrix (plugin) - QGIS
90s (or earlier) cross-world fantasy book with a circular river and character-class tattoos
Impossible darts scores
Going to get married soon, should I do it on Dec 31 or Jan 1?
Why is C++ initial allocation so much larger than C's?
Can the negators "jamais, rien, personne, plus, ni, aucun" be used in a single sentence?
Should my manager be aware of private LinkedIn approaches I receive? How to politely have this happen?
What happens when your group is victim of a surprise attack but you can't be surprised?
Plotting with different color for a single curve
Why do some games show lights shine through walls?
How to split an equation over two lines?
Inverse-quotes-quine
In the Marvel universe, can a human have a baby with any non-human?
Go Get the Six Six-Pack
Low-gravity Bronze Age fortifications
Fetch and print all properties of an object graph as string
Replace all occurrences with the properties of an objectReturn IEnumerable<KeyValuePair> from a private method; use Dictionary or anon. type?Pattern-matching-esque codeImplementation of stackWPF object model control with singleton and static messenger? ConditionalWeakTable?Safely order a list of objects by DateTimeBasic Pong GameTest all properties with single test functionPolymorphic DBConnector class exerciseEnumerate all members and types with specific attributes
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;
$begingroup$
Below I have setup an extension method that takes any object, cycles through its properties, and prints each out to a Console window in the format Name: Value
.
Specification / Scope:
- Handle only single objects (no collections)
code
public static string PropertiesToString<T>(this T obj, int tabs = 0) where T : class
int initTabs = tabs;
string result = string.Empty;
PropertyInfo[] propertyInfo = obj.GetType().GetProperties();
foreach (PropertyInfo property in propertyInfo)
string name = property.Name;
object value = property.GetValue(obj, null);
Type valueType = value.GetType();
if (valueType.IsValueType
return result;
Here is a class I'm using to test this code, along with the lines responsible for creating an instance of the class and writing its properties to the Console:
Class:
public class Circle : IShape
public Circle(double x, double y, double radius)
Center = new Point
X = x,
Y = y
;
Radius = radius;
public Point Center get; set;
public double Radius get; set;
public double Area(int precision = 2)
return Math.Round(Radius * Radius * Math.PI, precision);
Main:
public static void Main(string[] args)
IShape circle = new Circle(5, 5, 10);
Console.WriteLine(circle.PropertiesToString());
Console.ReadLine();
The above method will also cycle through nested objects and print those to the Console as well, adding in tabs for readability's sake.
I'm kind of unfamiliar with System.Reflection
and was wondering if there was a more efficient way I could approach doing something like this.
c# beginner recursion reflection extension-methods
$endgroup$
add a comment |
$begingroup$
Below I have setup an extension method that takes any object, cycles through its properties, and prints each out to a Console window in the format Name: Value
.
Specification / Scope:
- Handle only single objects (no collections)
code
public static string PropertiesToString<T>(this T obj, int tabs = 0) where T : class
int initTabs = tabs;
string result = string.Empty;
PropertyInfo[] propertyInfo = obj.GetType().GetProperties();
foreach (PropertyInfo property in propertyInfo)
string name = property.Name;
object value = property.GetValue(obj, null);
Type valueType = value.GetType();
if (valueType.IsValueType
return result;
Here is a class I'm using to test this code, along with the lines responsible for creating an instance of the class and writing its properties to the Console:
Class:
public class Circle : IShape
public Circle(double x, double y, double radius)
Center = new Point
X = x,
Y = y
;
Radius = radius;
public Point Center get; set;
public double Radius get; set;
public double Area(int precision = 2)
return Math.Round(Radius * Radius * Math.PI, precision);
Main:
public static void Main(string[] args)
IShape circle = new Circle(5, 5, 10);
Console.WriteLine(circle.PropertiesToString());
Console.ReadLine();
The above method will also cycle through nested objects and print those to the Console as well, adding in tabs for readability's sake.
I'm kind of unfamiliar with System.Reflection
and was wondering if there was a more efficient way I could approach doing something like this.
c# beginner recursion reflection extension-methods
$endgroup$
$begingroup$
The null-references are handled within the method by just addingstring.Empty
toresult
ifvalue == null
. Otherwise I was only considering using this method for single objects, not collections.
$endgroup$
– Delfino
8 hours ago
add a comment |
$begingroup$
Below I have setup an extension method that takes any object, cycles through its properties, and prints each out to a Console window in the format Name: Value
.
Specification / Scope:
- Handle only single objects (no collections)
code
public static string PropertiesToString<T>(this T obj, int tabs = 0) where T : class
int initTabs = tabs;
string result = string.Empty;
PropertyInfo[] propertyInfo = obj.GetType().GetProperties();
foreach (PropertyInfo property in propertyInfo)
string name = property.Name;
object value = property.GetValue(obj, null);
Type valueType = value.GetType();
if (valueType.IsValueType
return result;
Here is a class I'm using to test this code, along with the lines responsible for creating an instance of the class and writing its properties to the Console:
Class:
public class Circle : IShape
public Circle(double x, double y, double radius)
Center = new Point
X = x,
Y = y
;
Radius = radius;
public Point Center get; set;
public double Radius get; set;
public double Area(int precision = 2)
return Math.Round(Radius * Radius * Math.PI, precision);
Main:
public static void Main(string[] args)
IShape circle = new Circle(5, 5, 10);
Console.WriteLine(circle.PropertiesToString());
Console.ReadLine();
The above method will also cycle through nested objects and print those to the Console as well, adding in tabs for readability's sake.
I'm kind of unfamiliar with System.Reflection
and was wondering if there was a more efficient way I could approach doing something like this.
c# beginner recursion reflection extension-methods
$endgroup$
Below I have setup an extension method that takes any object, cycles through its properties, and prints each out to a Console window in the format Name: Value
.
Specification / Scope:
- Handle only single objects (no collections)
code
public static string PropertiesToString<T>(this T obj, int tabs = 0) where T : class
int initTabs = tabs;
string result = string.Empty;
PropertyInfo[] propertyInfo = obj.GetType().GetProperties();
foreach (PropertyInfo property in propertyInfo)
string name = property.Name;
object value = property.GetValue(obj, null);
Type valueType = value.GetType();
if (valueType.IsValueType
return result;
Here is a class I'm using to test this code, along with the lines responsible for creating an instance of the class and writing its properties to the Console:
Class:
public class Circle : IShape
public Circle(double x, double y, double radius)
Center = new Point
X = x,
Y = y
;
Radius = radius;
public Point Center get; set;
public double Radius get; set;
public double Area(int precision = 2)
return Math.Round(Radius * Radius * Math.PI, precision);
Main:
public static void Main(string[] args)
IShape circle = new Circle(5, 5, 10);
Console.WriteLine(circle.PropertiesToString());
Console.ReadLine();
The above method will also cycle through nested objects and print those to the Console as well, adding in tabs for readability's sake.
I'm kind of unfamiliar with System.Reflection
and was wondering if there was a more efficient way I could approach doing something like this.
c# beginner recursion reflection extension-methods
c# beginner recursion reflection extension-methods
edited 8 hours ago
dfhwze
3,1161 gold badge6 silver badges31 bronze badges
3,1161 gold badge6 silver badges31 bronze badges
asked 9 hours ago
DelfinoDelfino
1776 bronze badges
1776 bronze badges
$begingroup$
The null-references are handled within the method by just addingstring.Empty
toresult
ifvalue == null
. Otherwise I was only considering using this method for single objects, not collections.
$endgroup$
– Delfino
8 hours ago
add a comment |
$begingroup$
The null-references are handled within the method by just addingstring.Empty
toresult
ifvalue == null
. Otherwise I was only considering using this method for single objects, not collections.
$endgroup$
– Delfino
8 hours ago
$begingroup$
The null-references are handled within the method by just adding
string.Empty
to result
if value == null
. Otherwise I was only considering using this method for single objects, not collections.$endgroup$
– Delfino
8 hours ago
$begingroup$
The null-references are handled within the method by just adding
string.Empty
to result
if value == null
. Otherwise I was only considering using this method for single objects, not collections.$endgroup$
– Delfino
8 hours ago
add a comment |
2 Answers
2
active
oldest
votes
$begingroup$
You should have a guard clause against someone passing in null
PropertyInfo has a PropertyType and you should use that instead of
Type valueType = value.GetType();
as if value is null you will get a null reference error where PropertyType will give you the type of the property.
You will need to fix this line as well if value is null. Again you will get a null reference error
result += value.PropertiesToString(++tabs);
Better to compare types then their names. Instead of
valueType.Name.Equals("String")
use
valueType == typeof(string)
You should separate out gathering the properties and displaying them. I would have an extension method that returned IEnumerable> and then you could use linq to convert that into the strings and how you want it displayed.
Other things to consider is if you have two object that reference each other you will get a stack overflow.
I would recommend looking at https://docs.microsoft.com/en-us/dotnet/api/system.runtime.serialization.objectmanager?view=netframework-4.8 to see an example of an object walker. I think making the class IEnumerable is a bit confusion when learning and they would have been better making a method that returns IEnumerable. still a good place to start when learning about walking an object graph.
$endgroup$
add a comment |
$begingroup$
Bug
Your code does not handle value == null
everywhere.
object value = property.GetValue(obj, null);
Type valueType = value.GetType(); // <- can throw the infamous NRE
Review
- Use a clear method name
RenderProperties
. int tabs = 0
does not allow flexibility for rendering indents. Usestring indent = "t"
instead.this T obj
is fine, but I would preferthis T source
.string result = string.Empty;
andresult += ..
use aSystem.Text.StringBuilder
instead; much better memory management.- Use var syntax
var resultBuilder = new StringBuilder();
. obj.GetType().GetProperties();
should be extended to public, flatten hierarchy, instanceBindingFlags
properties withCanRead
,GetGetMethod(false) != null
andGetIndexParameters().Length == 0
to only include the publically accessible getter properties of the instance.valueType.Name.Equals("String")
should bevalue is String
. But perhaps you need a better strategy for determining which objects are complex ..for (int i = 0; i < tabs; i++) { result += ..
gets replaced completely withindent
as earlier specified.string.Format("0: 1n" ..
should useEnvironment.NewLine
, or even better use an overload onStringBuilder
calledAppendFormatLine
. Same thing in theelse
clause.PropertiesToString(value, ++tabs);
can be replaced byPropertiesToString(value, indent + indent);
.
Your Code Edited
I have decoupled retrieving properties from rendering. However, in another answer was suggested to go further and use a
tree walker
to adhere to best practices. That would be even better.I am asserting array or other collections do not require their items to be visited, and the complete object graph is a tree. You did never specify how to handle cyclic graphs, so they are out of scope :)
Render properties:
public static string RenderProperties<T>(this T source, string indent = "t")
where T : class
if (source == null) return string.Empty;
indent = indent ?? string.Empty;
var builder = new StringBuilder();
var properties = GetAccessibleProperties(source);
foreach (var property in properties)
RenderProperty(property, source, builder, indent);
return builder.ToString();
Render property:
private static void RenderProperty(
PropertyInfo property, object parent, StringBuilder builder, string indent)
Debug.Assert(property != null);
Debug.Assert(parent != null);
Debug.Assert(builder != null);
Debug.Assert(indent != null);
var name = property.Name;
var value = property.GetValue(parent, null); // <- need to handle exception?
if (value == null)
builder.AppendLine($"indentname: ");
else if (value.GetType().IsValueType
Get accessible properties:
private static IEnumerable<PropertyInfo> GetAccessibleProperties(object source)
BindingFlags.Public) // publicly accessible only
.Where(x =>
x.CanRead // must have getter
&& x.GetGetMethod(false) != null // must have public getter
&& x.GetIndexParameters().Length == 0); // must not be an indexer
return properties;
$endgroup$
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "196"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f222729%2ffetch-and-print-all-properties-of-an-object-graph-as-string%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
$begingroup$
You should have a guard clause against someone passing in null
PropertyInfo has a PropertyType and you should use that instead of
Type valueType = value.GetType();
as if value is null you will get a null reference error where PropertyType will give you the type of the property.
You will need to fix this line as well if value is null. Again you will get a null reference error
result += value.PropertiesToString(++tabs);
Better to compare types then their names. Instead of
valueType.Name.Equals("String")
use
valueType == typeof(string)
You should separate out gathering the properties and displaying them. I would have an extension method that returned IEnumerable> and then you could use linq to convert that into the strings and how you want it displayed.
Other things to consider is if you have two object that reference each other you will get a stack overflow.
I would recommend looking at https://docs.microsoft.com/en-us/dotnet/api/system.runtime.serialization.objectmanager?view=netframework-4.8 to see an example of an object walker. I think making the class IEnumerable is a bit confusion when learning and they would have been better making a method that returns IEnumerable. still a good place to start when learning about walking an object graph.
$endgroup$
add a comment |
$begingroup$
You should have a guard clause against someone passing in null
PropertyInfo has a PropertyType and you should use that instead of
Type valueType = value.GetType();
as if value is null you will get a null reference error where PropertyType will give you the type of the property.
You will need to fix this line as well if value is null. Again you will get a null reference error
result += value.PropertiesToString(++tabs);
Better to compare types then their names. Instead of
valueType.Name.Equals("String")
use
valueType == typeof(string)
You should separate out gathering the properties and displaying them. I would have an extension method that returned IEnumerable> and then you could use linq to convert that into the strings and how you want it displayed.
Other things to consider is if you have two object that reference each other you will get a stack overflow.
I would recommend looking at https://docs.microsoft.com/en-us/dotnet/api/system.runtime.serialization.objectmanager?view=netframework-4.8 to see an example of an object walker. I think making the class IEnumerable is a bit confusion when learning and they would have been better making a method that returns IEnumerable. still a good place to start when learning about walking an object graph.
$endgroup$
add a comment |
$begingroup$
You should have a guard clause against someone passing in null
PropertyInfo has a PropertyType and you should use that instead of
Type valueType = value.GetType();
as if value is null you will get a null reference error where PropertyType will give you the type of the property.
You will need to fix this line as well if value is null. Again you will get a null reference error
result += value.PropertiesToString(++tabs);
Better to compare types then their names. Instead of
valueType.Name.Equals("String")
use
valueType == typeof(string)
You should separate out gathering the properties and displaying them. I would have an extension method that returned IEnumerable> and then you could use linq to convert that into the strings and how you want it displayed.
Other things to consider is if you have two object that reference each other you will get a stack overflow.
I would recommend looking at https://docs.microsoft.com/en-us/dotnet/api/system.runtime.serialization.objectmanager?view=netframework-4.8 to see an example of an object walker. I think making the class IEnumerable is a bit confusion when learning and they would have been better making a method that returns IEnumerable. still a good place to start when learning about walking an object graph.
$endgroup$
You should have a guard clause against someone passing in null
PropertyInfo has a PropertyType and you should use that instead of
Type valueType = value.GetType();
as if value is null you will get a null reference error where PropertyType will give you the type of the property.
You will need to fix this line as well if value is null. Again you will get a null reference error
result += value.PropertiesToString(++tabs);
Better to compare types then their names. Instead of
valueType.Name.Equals("String")
use
valueType == typeof(string)
You should separate out gathering the properties and displaying them. I would have an extension method that returned IEnumerable> and then you could use linq to convert that into the strings and how you want it displayed.
Other things to consider is if you have two object that reference each other you will get a stack overflow.
I would recommend looking at https://docs.microsoft.com/en-us/dotnet/api/system.runtime.serialization.objectmanager?view=netframework-4.8 to see an example of an object walker. I think making the class IEnumerable is a bit confusion when learning and they would have been better making a method that returns IEnumerable. still a good place to start when learning about walking an object graph.
answered 7 hours ago
CharlesNRiceCharlesNRice
2,2896 silver badges13 bronze badges
2,2896 silver badges13 bronze badges
add a comment |
add a comment |
$begingroup$
Bug
Your code does not handle value == null
everywhere.
object value = property.GetValue(obj, null);
Type valueType = value.GetType(); // <- can throw the infamous NRE
Review
- Use a clear method name
RenderProperties
. int tabs = 0
does not allow flexibility for rendering indents. Usestring indent = "t"
instead.this T obj
is fine, but I would preferthis T source
.string result = string.Empty;
andresult += ..
use aSystem.Text.StringBuilder
instead; much better memory management.- Use var syntax
var resultBuilder = new StringBuilder();
. obj.GetType().GetProperties();
should be extended to public, flatten hierarchy, instanceBindingFlags
properties withCanRead
,GetGetMethod(false) != null
andGetIndexParameters().Length == 0
to only include the publically accessible getter properties of the instance.valueType.Name.Equals("String")
should bevalue is String
. But perhaps you need a better strategy for determining which objects are complex ..for (int i = 0; i < tabs; i++) { result += ..
gets replaced completely withindent
as earlier specified.string.Format("0: 1n" ..
should useEnvironment.NewLine
, or even better use an overload onStringBuilder
calledAppendFormatLine
. Same thing in theelse
clause.PropertiesToString(value, ++tabs);
can be replaced byPropertiesToString(value, indent + indent);
.
Your Code Edited
I have decoupled retrieving properties from rendering. However, in another answer was suggested to go further and use a
tree walker
to adhere to best practices. That would be even better.I am asserting array or other collections do not require their items to be visited, and the complete object graph is a tree. You did never specify how to handle cyclic graphs, so they are out of scope :)
Render properties:
public static string RenderProperties<T>(this T source, string indent = "t")
where T : class
if (source == null) return string.Empty;
indent = indent ?? string.Empty;
var builder = new StringBuilder();
var properties = GetAccessibleProperties(source);
foreach (var property in properties)
RenderProperty(property, source, builder, indent);
return builder.ToString();
Render property:
private static void RenderProperty(
PropertyInfo property, object parent, StringBuilder builder, string indent)
Debug.Assert(property != null);
Debug.Assert(parent != null);
Debug.Assert(builder != null);
Debug.Assert(indent != null);
var name = property.Name;
var value = property.GetValue(parent, null); // <- need to handle exception?
if (value == null)
builder.AppendLine($"indentname: ");
else if (value.GetType().IsValueType
Get accessible properties:
private static IEnumerable<PropertyInfo> GetAccessibleProperties(object source)
BindingFlags.Public) // publicly accessible only
.Where(x =>
x.CanRead // must have getter
&& x.GetGetMethod(false) != null // must have public getter
&& x.GetIndexParameters().Length == 0); // must not be an indexer
return properties;
$endgroup$
add a comment |
$begingroup$
Bug
Your code does not handle value == null
everywhere.
object value = property.GetValue(obj, null);
Type valueType = value.GetType(); // <- can throw the infamous NRE
Review
- Use a clear method name
RenderProperties
. int tabs = 0
does not allow flexibility for rendering indents. Usestring indent = "t"
instead.this T obj
is fine, but I would preferthis T source
.string result = string.Empty;
andresult += ..
use aSystem.Text.StringBuilder
instead; much better memory management.- Use var syntax
var resultBuilder = new StringBuilder();
. obj.GetType().GetProperties();
should be extended to public, flatten hierarchy, instanceBindingFlags
properties withCanRead
,GetGetMethod(false) != null
andGetIndexParameters().Length == 0
to only include the publically accessible getter properties of the instance.valueType.Name.Equals("String")
should bevalue is String
. But perhaps you need a better strategy for determining which objects are complex ..for (int i = 0; i < tabs; i++) { result += ..
gets replaced completely withindent
as earlier specified.string.Format("0: 1n" ..
should useEnvironment.NewLine
, or even better use an overload onStringBuilder
calledAppendFormatLine
. Same thing in theelse
clause.PropertiesToString(value, ++tabs);
can be replaced byPropertiesToString(value, indent + indent);
.
Your Code Edited
I have decoupled retrieving properties from rendering. However, in another answer was suggested to go further and use a
tree walker
to adhere to best practices. That would be even better.I am asserting array or other collections do not require their items to be visited, and the complete object graph is a tree. You did never specify how to handle cyclic graphs, so they are out of scope :)
Render properties:
public static string RenderProperties<T>(this T source, string indent = "t")
where T : class
if (source == null) return string.Empty;
indent = indent ?? string.Empty;
var builder = new StringBuilder();
var properties = GetAccessibleProperties(source);
foreach (var property in properties)
RenderProperty(property, source, builder, indent);
return builder.ToString();
Render property:
private static void RenderProperty(
PropertyInfo property, object parent, StringBuilder builder, string indent)
Debug.Assert(property != null);
Debug.Assert(parent != null);
Debug.Assert(builder != null);
Debug.Assert(indent != null);
var name = property.Name;
var value = property.GetValue(parent, null); // <- need to handle exception?
if (value == null)
builder.AppendLine($"indentname: ");
else if (value.GetType().IsValueType
Get accessible properties:
private static IEnumerable<PropertyInfo> GetAccessibleProperties(object source)
BindingFlags.Public) // publicly accessible only
.Where(x =>
x.CanRead // must have getter
&& x.GetGetMethod(false) != null // must have public getter
&& x.GetIndexParameters().Length == 0); // must not be an indexer
return properties;
$endgroup$
add a comment |
$begingroup$
Bug
Your code does not handle value == null
everywhere.
object value = property.GetValue(obj, null);
Type valueType = value.GetType(); // <- can throw the infamous NRE
Review
- Use a clear method name
RenderProperties
. int tabs = 0
does not allow flexibility for rendering indents. Usestring indent = "t"
instead.this T obj
is fine, but I would preferthis T source
.string result = string.Empty;
andresult += ..
use aSystem.Text.StringBuilder
instead; much better memory management.- Use var syntax
var resultBuilder = new StringBuilder();
. obj.GetType().GetProperties();
should be extended to public, flatten hierarchy, instanceBindingFlags
properties withCanRead
,GetGetMethod(false) != null
andGetIndexParameters().Length == 0
to only include the publically accessible getter properties of the instance.valueType.Name.Equals("String")
should bevalue is String
. But perhaps you need a better strategy for determining which objects are complex ..for (int i = 0; i < tabs; i++) { result += ..
gets replaced completely withindent
as earlier specified.string.Format("0: 1n" ..
should useEnvironment.NewLine
, or even better use an overload onStringBuilder
calledAppendFormatLine
. Same thing in theelse
clause.PropertiesToString(value, ++tabs);
can be replaced byPropertiesToString(value, indent + indent);
.
Your Code Edited
I have decoupled retrieving properties from rendering. However, in another answer was suggested to go further and use a
tree walker
to adhere to best practices. That would be even better.I am asserting array or other collections do not require their items to be visited, and the complete object graph is a tree. You did never specify how to handle cyclic graphs, so they are out of scope :)
Render properties:
public static string RenderProperties<T>(this T source, string indent = "t")
where T : class
if (source == null) return string.Empty;
indent = indent ?? string.Empty;
var builder = new StringBuilder();
var properties = GetAccessibleProperties(source);
foreach (var property in properties)
RenderProperty(property, source, builder, indent);
return builder.ToString();
Render property:
private static void RenderProperty(
PropertyInfo property, object parent, StringBuilder builder, string indent)
Debug.Assert(property != null);
Debug.Assert(parent != null);
Debug.Assert(builder != null);
Debug.Assert(indent != null);
var name = property.Name;
var value = property.GetValue(parent, null); // <- need to handle exception?
if (value == null)
builder.AppendLine($"indentname: ");
else if (value.GetType().IsValueType
Get accessible properties:
private static IEnumerable<PropertyInfo> GetAccessibleProperties(object source)
BindingFlags.Public) // publicly accessible only
.Where(x =>
x.CanRead // must have getter
&& x.GetGetMethod(false) != null // must have public getter
&& x.GetIndexParameters().Length == 0); // must not be an indexer
return properties;
$endgroup$
Bug
Your code does not handle value == null
everywhere.
object value = property.GetValue(obj, null);
Type valueType = value.GetType(); // <- can throw the infamous NRE
Review
- Use a clear method name
RenderProperties
. int tabs = 0
does not allow flexibility for rendering indents. Usestring indent = "t"
instead.this T obj
is fine, but I would preferthis T source
.string result = string.Empty;
andresult += ..
use aSystem.Text.StringBuilder
instead; much better memory management.- Use var syntax
var resultBuilder = new StringBuilder();
. obj.GetType().GetProperties();
should be extended to public, flatten hierarchy, instanceBindingFlags
properties withCanRead
,GetGetMethod(false) != null
andGetIndexParameters().Length == 0
to only include the publically accessible getter properties of the instance.valueType.Name.Equals("String")
should bevalue is String
. But perhaps you need a better strategy for determining which objects are complex ..for (int i = 0; i < tabs; i++) { result += ..
gets replaced completely withindent
as earlier specified.string.Format("0: 1n" ..
should useEnvironment.NewLine
, or even better use an overload onStringBuilder
calledAppendFormatLine
. Same thing in theelse
clause.PropertiesToString(value, ++tabs);
can be replaced byPropertiesToString(value, indent + indent);
.
Your Code Edited
I have decoupled retrieving properties from rendering. However, in another answer was suggested to go further and use a
tree walker
to adhere to best practices. That would be even better.I am asserting array or other collections do not require their items to be visited, and the complete object graph is a tree. You did never specify how to handle cyclic graphs, so they are out of scope :)
Render properties:
public static string RenderProperties<T>(this T source, string indent = "t")
where T : class
if (source == null) return string.Empty;
indent = indent ?? string.Empty;
var builder = new StringBuilder();
var properties = GetAccessibleProperties(source);
foreach (var property in properties)
RenderProperty(property, source, builder, indent);
return builder.ToString();
Render property:
private static void RenderProperty(
PropertyInfo property, object parent, StringBuilder builder, string indent)
Debug.Assert(property != null);
Debug.Assert(parent != null);
Debug.Assert(builder != null);
Debug.Assert(indent != null);
var name = property.Name;
var value = property.GetValue(parent, null); // <- need to handle exception?
if (value == null)
builder.AppendLine($"indentname: ");
else if (value.GetType().IsValueType
Get accessible properties:
private static IEnumerable<PropertyInfo> GetAccessibleProperties(object source)
BindingFlags.Public) // publicly accessible only
.Where(x =>
x.CanRead // must have getter
&& x.GetGetMethod(false) != null // must have public getter
&& x.GetIndexParameters().Length == 0); // must not be an indexer
return properties;
edited 6 hours ago
t3chb0t
36k7 gold badges58 silver badges133 bronze badges
36k7 gold badges58 silver badges133 bronze badges
answered 7 hours ago
dfhwzedfhwze
3,1161 gold badge6 silver badges31 bronze badges
3,1161 gold badge6 silver badges31 bronze badges
add a comment |
add a comment |
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f222729%2ffetch-and-print-all-properties-of-an-object-graph-as-string%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
$begingroup$
The null-references are handled within the method by just adding
string.Empty
toresult
ifvalue == null
. Otherwise I was only considering using this method for single objects, not collections.$endgroup$
– Delfino
8 hours ago