オブジェクトとそのすべてのリーフ値を次のような形式で出力できるクラスを探しています。
User
- Name: Gordon
- Age : 60
- WorkAddress
- Street: 10 Downing Street
- Town: London
- Country: UK
- HomeAddresses[0]
...
- HomeAddresses[1]
...
(またはより明確な形式)。これは次と同等です:
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; }
}
PropertyGridコントロールの文字列表現の一種。各タイプに多数のデザイナーセットを実装する必要はありません。
PHPには、これを行う var_dump と呼ばれるものがあります。これは印刷用なので、時計は使いたくありません。
このようなものが存在する場合、誰かが私を指すことができますか?または、賞金のために書いてください。
Sgmooreのリンクに投稿されたオブジェクトダンパー:
//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("{ }");
}
}
}
YAMLもこの目的に非常によく対応しています。これが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);
}
JSONシリアライザを使用できます。JSONシリアライザを使用すると、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());
2019に更新
GitHubで ObjectDumperプロジェクト を見つけることができます。また、NuGetパッケージマネージャーを使用してVisual Studioで 追加 を実行することもできます。
マークアップを使用している場合、 System.Web.ObjectInfo.Print
(ASP.NET Web Pages 2)はこれを実現し、HTML用に適切にフォーマットされています。
例えば:
@ObjectInfo.Print(new {
Foo = "Hello",
Bar = "World",
Qux = new {
Number = 42,
},
})
Webページで、以下を生成します。
これを行うために私が書いたビジュアルスタジオの拡張機能を次に示します。
https://visualstudiogallery.msdn.Microsoft.com/c6a21c68-f815-4895-999f-cd0885d8774f
動作中:
これは古い質問であることは知っていますが、私のために機能する代替案を捨てると思い、約2分かかりました。
Newtonsoft Json.NETをインストールします。 http://james.newtonking.com/json
(またはnugetバージョン) http://www.nuget.org/packages/newtonsoft.json/
参照アセンブリ:
using Newtonsoft.Json;
ログにJSON文字列をダンプします。
txtResult.Text = JsonConvert.SerializeObject(testObj);
少し反省すれば非常に簡単に書くことができます。次のようなもの:
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);
}
}
}
PrintArrayおよびPrintPropertyメソッドを作成できます。
便利なT.Dump()拡張メソッド があり、探している結果にかなり近いはずです。拡張メソッドとして、非侵襲的であり、すべてのPOCOオブジェクトで動作するはずです。
使用例
var model = new TestModel();
Console.WriteLine(model.Dump());
出力例
{
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
}
}
Chris Sのコードをコピーして貼り付けたくない場合は、Visual Studio 2008のサンプルにObjectDumperが付属しています。
ドライブ:\ Program Files\Microsoft Visual Studio 9.0\Samples\1033\LinqSamples\ObjectDumper
以下が代替案です。
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);
}
(レベル1に触れるだけで深さはありませんが、多くのことを言います)
ほとんどのクラスでは、 DataContractSerializer を使用できます
Blazorプロジェクトで同様の要件に出会い、オブジェクト(およびその子オブジェクト)のデータを画面に出力する次の非常に単純なコンポーネントを思い付きました。
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
});
}
}
次に、Blazorページのどこかに次のように貼り付けます。
<ObjectDumper ObjectToDump="@YourObjectToVisualise" />
次に、ボタンをレンダリングします。このボタンを押すと、バインドされたオブジェクトの現在の値を確認できます。
これをGitHubリポジトリに貼り付けました: tomRedox/BlazorObjectDumper