Cách tốt nhất để kết xuất toàn bộ các đối tượng vào một bản ghi trong C # là gì?


129

Vì vậy, để xem trạng thái của một đối tượng hiện tại trong thời gian chạy, tôi thực sự thích những gì cửa sổ Visual Studio Im Instant mang lại cho tôi. Chỉ làm đơn giản

? objectname

Sẽ cho tôi một 'bãi' được định dạng độc đáo của đối tượng.

Có một cách dễ dàng để làm điều này trong mã, vì vậy tôi có thể làm điều gì đó tương tự khi đăng nhập?


Cuối cùng, tôi đã sử dụng T.Dump khá nhiều. Đó là một giải pháp khá vững chắc - bạn chỉ cần cẩn thận với đệ quy.
Dan Esparza

Đây là một câu hỏi cũ, nhưng xuất hiện ở đầu của rất nhiều lượt truy cập tìm kiếm. Đối với độc giả trong tương lai: Xem phần này so với phần mở rộng . Làm việc tuyệt vời cho tôi trong VS2015.
Jesse Tốt

1
Cập nhật cho năm 2020 vì plugin VS không được duy trì và thiếu một số tính năng. Thư viện sau đây thực hiện cùng một mã trong mã - và nó có một vài tính năng bổ sung, ví dụ: nó theo dõi nơi nó đã được truy cập để tránh các vòng lặp: github.com/thomasgalliker/ObjectDumper
Nick Westgate 17/03

Câu trả lời:


55

Bạn có thể căn cứ một cái gì đó vào mã ObjectDumper đi kèm với các mẫu Linq .
Cũng đã xem câu trả lời của câu hỏi liên quan này để có được một mẫu.


5
Nó cũng không hoạt động cho các mảng (nó chỉ hiển thị loại và độ dài của mảng, nhưng không in nội dung của nó).
Konrad Morawski

5
gói nuget cho ObjectDumper hiện có sẵn. Nó cũng cung cấp một phương pháp mở rộng DumpToStringDumpđể Objectlớp. Tiện dụng.
IsmailS

2
w3wp.exegặp sự cố khi tôi cố gắng sử dụng ObjectDumpernhưRequest.DumpToString("aaa");
Paul

60

Đối với một đồ thị đối tượng lớn hơn, tôi thứ hai sử dụng Json nhưng với một chiến lược hơi khác. Đầu tiên tôi có một lớp tĩnh dễ gọi và với một phương thức tĩnh bao bọc chuyển đổi Json (lưu ý: có thể biến đây thành một phương thức mở rộng).

using Newtonsoft.Json;

public static class F
{
    public static string Dump(object obj)
    {
        return JsonConvert.SerializeObject(obj);
    }
}

Sau đó, trong của bạn Immediate Window,

var lookHere = F.Dump(myobj);

lookHere sẽ tự động hiển thị trong Localscửa sổ được thêm $ hoặc bạn có thể thêm đồng hồ vào đó. Ở phía bên phải của Valuecột trong thanh tra, có một kính lúp với một dấu mũ thả xuống bên cạnh nó. Chọn dấu mũ thả xuống và chọn Json visualizer.

Ảnh chụp màn hình cửa sổ Visual Studio 2013

Tôi đang sử dụng Visual Studio 2013.


2
SerializeObj -> serializeObject?
Wiseman

Rực rỡ, cảm ơn bạn. Tôi không thể cài đặt các công cụ gỡ lỗi cho Visual Studio trên máy chủ từ xa của mình và điều này hoạt động rất tốt trong ứng dụng asp.net mvc của tôi.
Liam Kernighan

1
Để định dạng đẹp, bạn có thể thực hiện:Newtonsoft.Json.JsonConvert.SerializeObject(sampleData, Formatting.Indented)
Zorgarath

dễ dàng hơn nhiều so với cố gắng làm nó bằng tay. Nó trở nên phức tạp
ahong

26

Tôi chắc chắn có nhiều cách tốt hơn để làm điều này, nhưng trước đây tôi đã sử dụng một phương thức giống như sau để tuần tự hóa một đối tượng thành một chuỗi mà tôi có thể đăng nhập:

  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;
  }

Bạn sẽ thấy rằng phương thức cũng có thể trả về ngoại lệ thay vì đối tượng được tuần tự hóa, vì vậy bạn sẽ muốn đảm bảo rằng các đối tượng bạn muốn đăng nhập được tuần tự hóa.


2
Theo các tính năng được thêm vào C # sau khi bạn trả lời câu hỏi có thể hữu ích để chỉ ra rằng việc triển khai này hoạt động độc đáo như một phương thức mở rộng. Nếu được áp dụng cho lớp Object và bạn tham chiếu tiện ích mở rộng ở mọi nơi bạn cần, thì đó có thể là một cách thuận tiện để gọi hàm.
Nikita G.

Tôi tiếp tục nhận được từ này : Failed to access type 'System.__ComObject' failed. Noob đến c #, sẽ đánh giá cao sự giúp đỡ.
GuySoft

1
@GuySoft Tôi nghi ngờ một trong các thuộc tính trên đối tượng của bạn, hoặc chính đối tượng đó, không được tuần tự hóa.
Bernhard Hofmann

Thật không may, bạn không thể sử dụng phương thức này trên các lớp mà không có hàm tạo không tham số. Chúng không được tuần tự hóa.
Jarekczek

22

Bạn có thể sử dụng Visual Studio Im Instant Window

Chỉ cần dán này ( actualrõ ràng thay đổi tên đối tượng của bạn):

Newtonsoft.Json.JsonConvert.SerializeObject(actual);

Nó nên in đối tượng trong JSON nhập mô tả hình ảnh ở đây

Bạn có thể sao chép nó qua công cụ văn bản văn bản hoặc notepad ++ và thay thế dấu ngoặc kép ( \") bằng "và dòng mới ( \r\n) bằng khoảng trống, sau đó xóa dấu ngoặc kép ( ") từ đầu và cuối và dán nó vào jsbeautifier để dễ đọc hơn.

CẬP NHẬT để bình luận của OP

public static class Dumper
{
    public static void Dump(this object obj)
    {
        Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(obj)); // your logger
    }
}

điều này sẽ cho phép bạn đổ bất kỳ đối tượng.

Hy vọng điều này sẽ giúp bạn tiết kiệm thời gian.


Cảm ơn. Có lẽ bạn đã không bắt được nó trong câu hỏi ban đầu của tôi, nhưng tôi chỉ ra rằng tôi đã biết về cửa sổ ngay lập tức và tôi muốn làm điều tương tự khi đăng nhập vào ứng dụng của mình.
Dan Esparza

@DanEsparza Console.Log(Newtonsoft.Json.JsonConvert.SerializeObject(actual));? :) và vâng tôi thực sự đã bỏ lỡ nó. Câu hỏi này xuất hiện khi bạn tìm kiếm google.co.uk/
Matas Vaitkevicius

2
FYI, khi bạn có chuỗi JSON trong chuỗi C #, hãy nhấp vào biểu tượng gián điệp ở bên phải chuỗi và chọn Trình hiển thị văn bản. Nó sẽ hiển thị một cửa sổ hiển thị phiên bản văn bản đơn giản của chuỗi JSON (không thoát dấu ngoặc kép hoặc \ r \ n).
Walter

16

ServiceStack.Text có một phương thức mở rộng T.Dump () thực hiện chính xác điều này, đệ quy tất cả các thuộc tính của bất kỳ loại nào trong một định dạng dễ đọc.

Ví dụ sử dụng:

var model = new TestModel();
Console.WriteLine(model.Dump());

và đầu ra:

{
    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
    }
}

1
Nó không hoạt động cho các lĩnh vực. OP đã hỏi rõ ràng về "toàn bộ đối tượng".
Konrad Morawski

5
He didn't say fields- ông nói entire objects, trong đó bao gồm các lĩnh vực. Anh ấy cũng đề cập đến tính năng Cửa sổ ngay lập tức của Visual Studio như một ví dụ về những gì anh ấy muốn đạt được ( "Chỉ cần làm một cách đơn giản ? objectnamesẽ cho tôi một 'bãi rác' được định dạng độc đáo của đối tượng" ). ? objectnamein ra tất cả các lĩnh vực là tốt. This has been immensely helpful - one of my most used extension methods to date- Tôi không nghi ngờ rằng nó hữu ích, chỉ là nó vứt bỏ toàn bộ vật thể.
Konrad Morawski

3
@KonradMorawski Sai toàn bộ đối tượng có nghĩa là kết xuất đệ quy của đối tượng, KHÔNG phải nó bao gồm các trường, có thể dễ dàng dẫn đến vòng lặp đệ quy vô hạn. Bạn không nên cho rằng những gì người khác đang ngụ ý. Câu trả lời của tôi vừa có liên quan vừa hữu ích, bình chọn xuống + bình luận của bạn thì không.
huyền thoại

1
@mythz tất nhiên bạn cần phải ngăn chặn tràn ngăn xếp (ví dụ: mọi Int32trường đều có một MaxValuetrường, đó là Int32chính nó ...), đó là một điểm tốt, nhưng nó không thay đổi thực tế rằng các đối tượng - và chắc chắn là toàn bộ các đối tượng - bao gồm các trường, quá, không chỉ các thuộc tính. Hơn thế nữa (bạn không giải quyết vấn đề đó), ? objectnametrong các trường Immediate Window không hiển thị - mà không kích hoạt một vòng lặp vô hạn. Nếu đó là về downvote của tôi, tôi có thể rút nó (nếu bạn cho tôi bằng cách mở khóa, đó là). Tôi không đồng ý về nguyên tắc nào.
Konrad Morawski

4
-1 về cơ bản là một câu trả lời chỉ liên kết, mặc dù nó có vẻ tuyệt vời nếu tôi có thể sử dụng nó! Có lẽ tôi bị mù, nhưng tôi không thể tìm thấy nguồn thông qua liên kết đó; Hai thư mục tải lên đều trống. Là mã quá dài để bao gồm trong câu trả lời?

14

Đây là một cách đơn giản ngu ngốc để viết một đối tượng phẳng, được định dạng độc đáo:

using Newtonsoft.Json.Linq;

Debug.WriteLine("The object is " + JObject.FromObject(theObjectToDump).ToString());

Điều đang xảy ra là đối tượng trước tiên được chuyển đổi thành biểu diễn bên trong JSON JObject.FromObject, sau đó được chuyển đổi thành chuỗi JSON theo ToString. (Và tất nhiên, một chuỗi JSON là một đại diện rất đẹp của một đối tượng đơn giản, đặc biệt là vì ToStringsẽ bao gồm các dòng mới và thụt lề.) "ToString" dĩ nhiên là không liên quan (như được ngụ ý bằng cách sử dụng +để nối một chuỗi và một đối tượng), nhưng Tôi muốn chỉ định nó ở đây.


5
JsonConvert.SerializeObject (đánh giá cao, định dạng. Nội dung) để đọc thoải mái trong nhật ký
Tertium

1
HotLicks - Tôi muốn truyền đạt cho bạn tầm quan trọng của sự đóng góp này đối với tôi ngay bây giờ. Tôi có một yêu cầu để cung cấp một cuộc kiểm toán về những gì đã thay đổi trong quá trình cập nhật và bạn vừa mới căng thẳng từ mức độ 'hoảng loạn' xuống mức 'lo lắng' có thể kiểm soát được. Cảm ơn ngài, chúc ngài có một cuộc sống rất dài và may mắn
Iofacture

4

Bạn có thể sử dụng sự phản chiếu và lặp qua tất cả các thuộc tính đối tượng, sau đó lấy các giá trị của chúng và lưu chúng vào nhật ký. Định dạng thực sự không quan trọng (bạn có thể sử dụng \ t để thụt lề một thuộc tính đối tượng và các giá trị của nó):

MyObject
    Property1 = value
    Property2 = value2
    OtherObject
       OtherProperty = value ...

4

Những gì tôi thích làm là ghi đè ToString () để tôi nhận được đầu ra hữu ích hơn ngoài tên loại. Điều này rất hữu ích trong trình gỡ lỗi, bạn có thể xem thông tin bạn muốn về một đối tượng mà không cần phải mở rộng nó.


3

Tôi tìm thấy một thư viện có tên ObjectPrinter cho phép dễ dàng kết xuất các đối tượng và bộ sưu tập thành chuỗi (và hơn thế nữa). Nó làm chính xác những gì tôi cần.


3

Sau đây là một phiên bản khác thực hiện điều tương tự (và xử lý các thuộc tính lồng nhau), mà tôi nghĩ là đơn giản hơn (không phụ thuộc vào các thư viện bên ngoài và có thể được sửa đổi dễ dàng để thực hiện những việc khác ngoài đăng nhập):

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"));
    }
}

1
điều này sẽ chết một cách khủng khiếp nếu bạn có một Datetài sản trong đối tượng bên trong của mình ... chỉ cần nói ...
Noctis

2

Bạn có thể viết phương thức WriteLine của riêng bạn-

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());
    }

Sử dụng nó như-

WriteLine(myObject);

Để viết một bộ sưu tập chúng ta có thể sử dụng-

 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);
            }
        }   

Phương pháp có thể trông giống như-

 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());
        }
    }

Sử dụng if, else ifvà kiểm tra giao diện, thuộc tính, loại cơ sở, v.v. và đệ quy (vì đây là phương pháp đệ quy) theo cách này chúng ta có thể đạt được một trình điều khiển đối tượng, nhưng chắc chắn là tẻ nhạt. Sử dụng công cụ nhảy đối tượng từ Mẫu LINQ của Microsoft sẽ tiết kiệm thời gian của bạn.


Vì tò mò: Làm thế nào để điều này xử lý các mảng hoặc danh sách? Hoặc các thuộc tính tham chiếu các đối tượng cha mẹ?
Dan Esparza

@DanEsparza Nhờ chỉ cho tôi cách cụ thể hơn.
Hồi giáo Ariful

2

Dựa trên câu trả lời của @engineforce, tôi đã tạo lớp này mà tôi đang sử dụng trong dự án PCL của Giải pháp Xamarin:

/// <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;
    }
}

0

Tất cả các đường dẫn ở trên đều cho rằng các đối tượng của bạn được tuần tự hóa thành XML hoặc JSON
hoặc bạn phải thực hiện giải pháp của riêng mình.

Nhưng cuối cùng bạn vẫn đi đến điểm phải giải quyết các vấn đề như

  • đệ quy trong các đối tượng
  • các đối tượng không tuần tự hóa
  • ngoại lệ
  • ...

Thêm vào nhật ký bạn muốn biết thêm thông tin:

  • khi sự kiện xảy ra
  • cuộc gọi
  • cái đó
  • những gì trong phiên web
  • địa chỉ IP nào
  • url
  • ...

Có giải pháp tốt nhất giải quyết tất cả những điều này và nhiều hơn nữa.
Sử dụng gói Nuget này: Desharp .
Đối với tất cả các loại ứng dụng - cả ứng dụng web và máy tính để bàn .
Xem tài liệu của Desharp Github . Nó có nhiều tùy chọn cấu hình .

Chỉ cần gọi bất cứ nơi nào:

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
  • nó có thể lưu nhật ký bằng HTML đẹp (hoặc ở định dạng văn bản, có thể định cấu hình)
  • có thể viết tùy ý trong luồng nền (có thể định cấu hình)
  • nó có các tùy chọn cho độ sâu đối tượng tối đa và độ dài chuỗi tối đa (có thể định cấu hình)
  • nó sử dụng các vòng lặp cho các đối tượng lặp lại và phản xạ ngược cho mọi thứ khác,
    thực sự cho bất cứ điều gì bạn có thể tìm thấy trong môi trường .NET .

Tôi tin rằng nó sẽ giúp.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.