因此,对于在运行时查看当前对象的状态,我真的很喜欢Visual Studio Instant窗口提供的功能。只是做一个简单的
? objectname
会给我一个很好格式化的对象“转储”。
有没有一种简单的方法可以在代码中执行此操作,因此在登录时可以执行类似的操作?
因此,对于在运行时查看当前对象的状态,我真的很喜欢Visual Studio Instant窗口提供的功能。只是做一个简单的
? objectname
会给我一个很好格式化的对象“转储”。
有没有一种简单的方法可以在代码中执行此操作,因此在登录时可以执行类似的操作?
Answers:
w3wp.exe
崩溃当我尝试使用ObjectDumper
类似Request.DumpToString("aaa");
对于较大的对象图,我第二次使用Json,但策略略有不同。首先,我有一个易于调用的静态类,并带有包装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 visualizer。
我正在使用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 to C#,不胜感激。
您可以使用Visual Studio立即窗口
只需粘贴(actual
显然更改为您的对象名称):
Newtonsoft.Json.JsonConvert.SerializeObject(actual);
它应该以JSON打印对象
您应该可以通过textmechanic文本工具或记事本++复制它\"
,"
并\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”当然是多余的(因为使用+
concat字符串和对象来隐含它),但是我有点想在这里指定。
您可以使用反射并遍历所有对象属性,然后获取它们的值并将其保存到日志中。格式确实很简单(您可以使用\ t缩进对象属性及其值):
MyObject
Property1 = value
Property2 = value2
OtherObject
OtherProperty = value ...
我喜欢做的是重写ToString(),以便获得类型名称之外的更多有用输出。这在调试器中很方便,您无需扩展即可查看所需的对象信息。
我找到了一个名为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 Sample中的对象转储器可以节省您的时间。
基于@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
我相信这会有所帮助。