したがって、実行時に現在のオブジェクトの状態を表示するには、Visual Studioのイミディエイトウィンドウで表示されるものが本当に気に入っています。単純に
? objectname
オブジェクトの適切にフォーマットされた「ダンプ」を取得します。
コードでこれを行う簡単な方法はありますか?ログに記録するときに同様のことができますか?
したがって、実行時に現在のオブジェクトの状態を表示するには、Visual Studioのイミディエイトウィンドウで表示されるものが本当に気に入っています。単純に
? objectname
オブジェクトの適切にフォーマットされた「ダンプ」を取得します。
コードでこれを行う簡単な方法はありますか?ログに記録するときに同様のことができますか?
回答:
w3wp.exe
のObjectDumper
ように使用しようとするとクラッシュするRequest.DumpToString("aaa");
より大きなオブジェクトグラフの場合は、Jsonの使用に2番目ですが、戦略は少し異なります。最初に、呼び出しが簡単で、Json変換をラップする静的メソッドを持つ静的クラスがあります(注:これを拡張メソッドにすることができます)。
using Newtonsoft.Json;
public static class F
{
public static string Dump(object obj)
{
return JsonConvert.SerializeObject(obj);
}
}
次にImmediate Window
、
var lookHere = F.Dump(myobj);
lookHereは、Locals
先頭に$が付いたウィンドウに自動的に表示されます。または、ウォッチを追加することもできます。Value
インスペクタのカラムの右側に、ドロップダウンキャレットが付いた拡大鏡があります。ドロップダウンキャレットを選択し、Jsonビジュアライザーを選択します。
Visual Studio 2013を使用しています。
Newtonsoft.Json.JsonConvert.SerializeObject(sampleData, Formatting.Indented)
これを行うにはもっと良い方法があると確信していますが、以前は次のようなメソッドを使用して、オブジェクトをログに記録できる文字列にシリアル化しています。
private string ObjectToXml(object output)
{
string objectAsXmlString;
System.Xml.Serialization.XmlSerializer xs = new System.Xml.Serialization.XmlSerializer(output.GetType());
using (System.IO.StringWriter sw = new System.IO.StringWriter())
{
try
{
xs.Serialize(sw, output);
objectAsXmlString = sw.ToString();
}
catch (Exception ex)
{
objectAsXmlString = ex.ToString();
}
}
return objectAsXmlString;
}
メソッドもシリアル化されたオブジェクトではなく例外を返す可能性があることがわかるので、ログに記録するオブジェクトがシリアル化可能であることを確認する必要があります。
Failed to access type 'System.__ComObject' failed
。Noobからc#へ、助けていただければ幸いです。
Visual Studioイミディエイトウィンドウを使用できます
これを貼り付けるだけです(actual
明らかにオブジェクト名を変更してください)。
Newtonsoft.Json.JsonConvert.SerializeObject(actual);
オブジェクトをJSONで出力する必要があります
textmechanicテキストツールまたはnotepad ++を介してそれをコピーし、エスケープされた引用符(\"
)を"
改行(\r\n
)で空のスペースに置き換えて"
から、最初と最後から二重引用符()を削除し、それをjsbeautifierに貼り付けて読みやすくします。
OPのコメントを更新
public static class Dumper
{
public static void Dump(this object obj)
{
Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(obj)); // your logger
}
}
これにより、オブジェクトをダンプできます。
これにより時間を節約できることを願っています。
Console.Log(Newtonsoft.Json.JsonConvert.SerializeObject(actual));
?:)そしてはい、私は確かにそれを逃しました。この質問は、google.co.uk
ServiceStack.TextにはT.Dump()拡張メソッドがあります正確にこれがあり、あらゆるタイプのすべてのプロパティを読みやすい形式で再帰的にダンプします。
使用例:
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
}
}
He didn't say fields
-彼は言ったentire objects
、それは分野を含みます。彼はまた、達成したいことの例としてVisual Studioのイミディエイトウィンドウ機能に言及しました(「単純な操作? objectname
を行うだけで、オブジェクトの適切にフォーマットされた 'ダンプ'が得られます」)。? objectname
すべてのフィールドも出力します。This has been immensely helpful - one of my most used extension methods to date
-私はそれが有用であることに疑問を感じていません。それはオブジェクト全体をダンプすることだけです。
Int32
フィールドにフィールド自体MaxValue
がありInt32
ます...)。 -プロパティだけでなく、フィールドも含まれます。さらに、(表示さ? objectname
れなかった)表示フィールドにImmediate Window
は、無限ループをトリガーせずに表示されます。それが私の反対票の場合は、取り下げることができます(ロックを解除して許可した場合)。とにかく私は原則的に同意しません。
以下は、きれいにフォーマットされた、平らなオブジェクトを書く愚かな単純な方法です:
using Newtonsoft.Json.Linq;
Debug.WriteLine("The object is " + JObject.FromObject(theObjectToDump).ToString());
何が起こっているのかというと、オブジェクトは最初にによってJSON内部表現にJObject.FromObject
変換され、次にによってJSON文字列に変換されますToString
。(そしてもちろん、JSON文字列は、特にToString
改行とインデントが含まれるため、単純なオブジェクトの非常に優れた表現です。) "ToString"はもちろん無関係です(+
文字列とオブジェクトを連結するためにを使用することで暗示されているため)。ここで指定したいです。
リフレクションを使用してすべてのオブジェクトプロパティをループし、それらの値を取得してログに保存できます。書式設定は非常に簡単です(\ tを使用してオブジェクトのプロパティとその値をインデントできます)。
MyObject
Property1 = value
Property2 = value2
OtherObject
OtherProperty = value ...
ObjectPrinterと呼ばれるライブラリを見つけました。このライブラリを使用すると、オブジェクトやコレクションを簡単に文字列(およびその他)にダンプできます。それはまさに私が必要としたことをします。
以下は、同じことを行う(およびネストされたプロパティを処理する)別のバージョンです。これは、より単純だと思います(外部ライブラリへの依存関係がなく、簡単に変更してロギング以外のことを実行できます)。
public class ObjectDumper
{
public static string Dump(object obj)
{
return new ObjectDumper().DumpObject(obj);
}
StringBuilder _dumpBuilder = new StringBuilder();
string DumpObject(object obj)
{
DumpObject(obj, 0);
return _dumpBuilder.ToString();
}
void DumpObject(object obj, int nestingLevel = 0)
{
var nestingSpaces = "".PadLeft(nestingLevel * 4);
if (obj == null)
{
_dumpBuilder.AppendFormat("{0}null\n", nestingSpaces);
}
else if (obj is string || obj.GetType().IsPrimitive)
{
_dumpBuilder.AppendFormat("{0}{1}\n", nestingSpaces, obj);
}
else if (ImplementsDictionary(obj.GetType()))
{
using (var e = ((dynamic)obj).GetEnumerator())
{
var enumerator = (IEnumerator)e;
while (enumerator.MoveNext())
{
dynamic p = enumerator.Current;
var key = p.Key;
var value = p.Value;
_dumpBuilder.AppendFormat("{0}{1} ({2})\n", nestingSpaces, key, value != null ? value.GetType().ToString() : "<null>");
DumpObject(value, nestingLevel + 1);
}
}
}
else if (obj is IEnumerable)
{
foreach (dynamic p in obj as IEnumerable)
{
DumpObject(p, nestingLevel);
}
}
else
{
foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(obj))
{
string name = descriptor.Name;
object value = descriptor.GetValue(obj);
_dumpBuilder.AppendFormat("{0}{1} ({2})\n", nestingSpaces, name, value != null ? value.GetType().ToString() : "<null>");
DumpObject(value, nestingLevel + 1);
}
}
}
bool ImplementsDictionary(Type t)
{
return t.GetInterfaces().Any(i => i.Name.Contains("IDictionary"));
}
}
Date
内部オブジェクトにプロパティがある場合、これはひどく死にます...ただ言う...
独自のWriteLineメソッドを記述できます-
public static void WriteLine<T>(T obj)
{
var t = typeof(T);
var props = t.GetProperties();
StringBuilder sb = new StringBuilder();
foreach (var item in props)
{
sb.Append($"{item.Name}:{item.GetValue(obj,null)}; ");
}
sb.AppendLine();
Console.WriteLine(sb.ToString());
}
次のように使用します
WriteLine(myObject);
私たちが使用できるコレクションを書くために-
var ifaces = t.GetInterfaces();
if (ifaces.Any(o => o.Name.StartsWith("ICollection")))
{
dynamic lst = t.GetMethod("GetEnumerator").Invoke(obj, null);
while (lst.MoveNext())
{
WriteLine(lst.Current);
}
}
メソッドは次のようになります。
public static void WriteLine<T>(T obj)
{
var t = typeof(T);
var ifaces = t.GetInterfaces();
if (ifaces.Any(o => o.Name.StartsWith("ICollection")))
{
dynamic lst = t.GetMethod("GetEnumerator").Invoke(obj, null);
while (lst.MoveNext())
{
WriteLine(lst.Current);
}
}
else if (t.GetProperties().Any())
{
var props = t.GetProperties();
StringBuilder sb = new StringBuilder();
foreach (var item in props)
{
sb.Append($"{item.Name}:{item.GetValue(obj, null)}; ");
}
sb.AppendLine();
Console.WriteLine(sb.ToString());
}
}
この方法if, else if
でインターフェイス、属性、ベースタイプなどと再帰(これは再帰的なメソッドであるため)を使用してチェックすることで、オブジェクトダンパーを実現できますが、確かに面倒です。MicrosoftのLINQサンプルのオブジェクトダンパーを使用すると、時間を節約できます。
@engineforceの回答に基づいて、XamarinソリューションのPCLプロジェクトで使用するこのクラスを作成しました。
/// <summary>
/// Based on: https://stackoverflow.com/a/42264037/6155481
/// </summary>
public class ObjectDumper
{
public static string Dump(object obj)
{
return new ObjectDumper().DumpObject(obj);
}
StringBuilder _dumpBuilder = new StringBuilder();
string DumpObject(object obj)
{
DumpObject(obj, 0);
return _dumpBuilder.ToString();
}
void DumpObject(object obj, int nestingLevel)
{
var nestingSpaces = "".PadLeft(nestingLevel * 4);
if (obj == null)
{
_dumpBuilder.AppendFormat("{0}null\n", nestingSpaces);
}
else if (obj is string || obj.GetType().GetTypeInfo().IsPrimitive || obj.GetType().GetTypeInfo().IsEnum)
{
_dumpBuilder.AppendFormat("{0}{1}\n", nestingSpaces, obj);
}
else if (ImplementsDictionary(obj.GetType()))
{
using (var e = ((dynamic)obj).GetEnumerator())
{
var enumerator = (IEnumerator)e;
while (enumerator.MoveNext())
{
dynamic p = enumerator.Current;
var key = p.Key;
var value = p.Value;
_dumpBuilder.AppendFormat("{0}{1} ({2})\n", nestingSpaces, key, value != null ? value.GetType().ToString() : "<null>");
DumpObject(value, nestingLevel + 1);
}
}
}
else if (obj is IEnumerable)
{
foreach (dynamic p in obj as IEnumerable)
{
DumpObject(p, nestingLevel);
}
}
else
{
foreach (PropertyInfo descriptor in obj.GetType().GetRuntimeProperties())
{
string name = descriptor.Name;
object value = descriptor.GetValue(obj);
_dumpBuilder.AppendFormat("{0}{1} ({2})\n", nestingSpaces, name, value != null ? value.GetType().ToString() : "<null>");
// TODO: Prevent recursion due to circular reference
if (name == "Self" && HasBaseType(obj.GetType(), "NSObject"))
{
// In ObjC I need to break the recursion when I find the Self property
// otherwise it will be an infinite recursion
Console.WriteLine($"Found Self! {obj.GetType()}");
}
else
{
DumpObject(value, nestingLevel + 1);
}
}
}
}
bool HasBaseType(Type type, string baseTypeName)
{
if (type == null) return false;
string typeName = type.Name;
if (baseTypeName == typeName) return true;
return HasBaseType(type.GetTypeInfo().BaseType, baseTypeName);
}
bool ImplementsDictionary(Type t)
{
return t is IDictionary;
}
}
上記のすべてのパスは、オブジェクトがXMLまたはJSONにシリアル化可能であるか
、独自のソリューションを実装する必要があることを前提としています。
しかし、最終的には、次のような問題を解決する必要がある点に到達します
さらに、詳細情報が必要なログ:
これらすべてを解決する最良のソリューションがあります。
このNugetパッケージを使用してください:Desharp。
すべてのタイプのアプリケーション(Webアプリケーションとデスクトップアプリケーションの両方)。Desharp Githubのドキュメントを
参照してください。それは持っている多くの設定オプションを。
どこにでも電話する:
Desharp.Debug.Log(anyException);
Desharp.Debug.Log(anyCustomValueObject);
Desharp.Debug.Log(anyNonserializableObject);
Desharp.Debug.Log(anyFunc);
Desharp.Debug.Log(anyFunc, Desharp.Level.EMERGENCY); // you can store into different files
私はそれが役立つと信じています。