วิธีใดเป็นวิธีที่ดีที่สุดในการถ่ายโอนวัตถุทั้งหมดไปยังบันทึกใน C #


129

ดังนั้นสำหรับการดูสถานะของวัตถุปัจจุบันที่รันไทม์ฉันชอบสิ่งที่หน้าต่าง Visual Studio Immediate ให้ฉันมาก เพียงแค่ทำง่ายๆ

? objectname

จะให้ 'การถ่ายโอนข้อมูล' ของวัตถุที่มีรูปแบบสวยงาม

มีวิธีง่ายๆในการทำโค้ดเพื่อให้ฉันสามารถทำสิ่งที่คล้ายกันเมื่อเข้าสู่ระบบได้หรือไม่


ในท้ายที่สุดฉันก็ใช้ T.Dump ไม่น้อย เป็นวิธีแก้ปัญหาที่ค่อนข้างมั่นคงคุณเพียงแค่ต้องระวังการเกิดซ้ำ
Dan Esparza

นี่เป็นคำถามเก่า แต่ปรากฏอยู่ในอันดับต้น ๆ ของการค้นหาจำนวนมาก สำหรับผู้อ่านในอนาคต: ดูนี้เทียบกับส่วนขยาย ทำงานได้ดีสำหรับฉันใน VS2015
Jesse Good

1
อัปเดตสำหรับปี 2020 เนื่องจากปลั๊กอิน VS นั้นไม่ได้รับการดูแลและขาดคุณสมบัติบางอย่าง ไลบรารีต่อไปนี้ทำสิ่งเดียวกันในรหัส - และมีคุณสมบัติพิเศษบางอย่างเช่นติดตามสถานที่ที่เคยเยี่ยมชมแล้วเพื่อหลีกเลี่ยงการวนซ้ำ: github.com/thomasgalliker/ObjectDumper
Nick Westgate

คำตอบ:


55

คุณสามารถฐานบางอย่างในรหัส ObjectDumper ที่จัดส่งด้วยตัวอย่าง Linq
ลองดูคำตอบของคำถามที่เกี่ยวข้องนี้เพื่อรับตัวอย่าง


5
นอกจากนี้ยังใช้ไม่ได้กับอาร์เรย์ (เพียงแค่แสดงประเภทและความยาวของอาร์เรย์ แต่ไม่พิมพ์เนื้อหา)
Konrad Morawski

5
แพ็คเกจ nuget สำหรับ ObjectDumperพร้อมใช้งานแล้ว นอกจากนี้ยังมีวิธีการขยายDumpToStringและDumpในObjectชั้นเรียน มีประโยชน์
IsmailS

2
w3wp.exeขัดข้องเมื่อฉันพยายามใช้ObjectDumperเช่นRequest.DumpToString("aaa");
พอล

60

สำหรับกราฟวัตถุขนาดใหญ่ฉันใช้ 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 Locals

ฉันใช้ Visual Studio 2013


2
SerializeObj -> SerializeObject?
Wiseman

ยอดเยี่ยมขอบคุณ ฉันไม่สามารถติดตั้งเครื่องมือดีบักสำหรับ Visual Studio บนเซิร์ฟเวอร์ระยะไกลของฉันได้และสิ่งนี้ทำงานได้ดีมากในแอป asp.net mvc ของฉัน
Liam Kernighan

1
สำหรับการจัดรูปแบบที่ดีคุณสามารถทำได้:Newtonsoft.Json.JsonConvert.SerializeObject(sampleData, Formatting.Indented)
Zorgarath

ง่ายกว่าการพยายามทำด้วยมือมาก จะได้รับความซับซ้อน
Ahong

26

ฉันแน่ใจว่ามีวิธีที่ดีกว่านี้ในการทำเช่นนี้ แต่ในอดีตฉันเคยใช้วิธีการต่อไปนี้เพื่อทำให้วัตถุเป็นอนุกรมเป็นสตริงที่ฉันสามารถบันทึกได้:

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

คุณจะเห็นว่าเมธอดนี้อาจส่งคืนข้อยกเว้นแทนที่จะเป็นอ็อบเจ็กต์ที่ทำให้เป็นอนุกรมดังนั้นคุณต้องแน่ใจว่าอ็อบเจ็กต์ที่คุณต้องการบันทึกนั้นสามารถต่ออนุกรมกันได้


2
ในแง่ของคุณสมบัติที่เพิ่มใน C # หลังจากที่คุณตอบคำถามอาจเป็นประโยชน์ในการชี้ให้เห็นว่าการใช้งานนี้ทำงานได้ดีเป็นวิธีการขยาย หากใช้กับคลาส Object และคุณอ้างอิงส่วนขยายทุกที่ที่คุณต้องการอาจเป็นวิธีที่สะดวกในการเรียกใช้ฟังก์ชัน
Nikita G.

ฉันได้รับจากสิ่งนี้: Failed to access type 'System.__ComObject' failed. Noob ถึง c # ขอขอบคุณสำหรับความช่วยเหลือ
GuySoft

1
@GuySoft ฉันสงสัยว่าคุณสมบัติอย่างใดอย่างหนึ่งบนวัตถุของคุณหรือตัววัตถุนั้นไม่สามารถต่อเนื่องกันได้
Bernhard Hofmann

คุณไม่สามารถใช้วิธีนี้กับคลาสที่ไม่มีตัวสร้างแบบไม่มีพารามิเตอร์ได้ ไม่สามารถต่ออนุกรมกันได้
Jarekczek

22

คุณสามารถใช้ Visual Studio Immediate Window

เพียงวางสิ่งนี้ (เปลี่ยนactualเป็นชื่อวัตถุของคุณอย่างชัดเจน):

Newtonsoft.Json.JsonConvert.SerializeObject(actual);

ควรพิมพ์วัตถุใน JSON ป้อนคำอธิบายภาพที่นี่

คุณควรจะสามารถคัดลอกได้บนเครื่องมือ textmechanic text toolหรือnotepad ++และแทนที่เครื่องหมายคำพูดที่ใช้ Escape ( \") ด้วย"และขึ้นบรรทัดใหม่ ( \r\n) ด้วยช่องว่างจากนั้นลบเครื่องหมายคำพูดคู่ ( ") จากจุดเริ่มต้นและจุดสิ้นสุดและวางลงในjsbeautifierเพื่อให้อ่านได้ง่ายขึ้น

อัปเดตความคิดเห็นของ OP

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

สิ่งนี้จะช่วยให้คุณสามารถถ่ายโอนวัตถุใด ๆ

หวังว่านี่จะช่วยคุณประหยัดเวลาได้บ้าง


ขอบคุณ บางทีคุณอาจไม่เข้าใจในคำถามเดิมของฉัน แต่ฉันระบุว่าฉันรู้เกี่ยวกับหน้าต่างทันทีแล้วและฉันต้องการทำสิ่งเดียวกันนี้เมื่อเข้าสู่ระบบแอป
Dan Esparza

@DanEsparza Console.Log(Newtonsoft.Json.JsonConvert.SerializeObject(actual));? :) และใช่ฉันพลาดไปแล้ว คำถามนี้เกิดขึ้นเมื่อคุณค้นหาgoogle.co.uk/…
Matas Vaitkevicius

2
FYI เมื่อคุณมีสตริง JSON ในสตริง C # ให้คลิกที่ไอคอนสปายกลาสทางด้านขวาของสตริงแล้วเลือก Text Visualizer มันจะแสดงหน้าต่างที่แสดงสตริง JSON เวอร์ชันข้อความธรรมดา (ไม่ใช่เครื่องหมายคำพูดที่ใช้ Escape หรือ \ r \ n)
Walter

17

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

1
ใช้ไม่ได้กับเขตข้อมูล OP กำลังถามอย่างชัดเจนเกี่ยวกับ "วัตถุทั้งหมด"
Konrad Morawski

5
He didn't say fields- เขากล่าวentire objectsซึ่งรวมถึงเขตข้อมูล นอกจากนี้เขายังกล่าวถึงคุณลักษณะ Immediate Window ของ Visual Studio เพื่อเป็นตัวอย่างสิ่งที่เขาต้องการบรรลุ ( "เพียงแค่ทำง่ายๆ? objectnameก็จะทำให้ฉันมี 'การถ่ายโอนข้อมูล' ของวัตถุในรูปแบบที่สวยงาม ) ? objectnameพิมพ์ฟิลด์ทั้งหมดด้วย This has been immensely helpful - one of my most used extension methods to date- ฉันไม่ได้ตั้งคำถามว่ามันมีประโยชน์เพียงแค่ทิ้งวัตถุทั้งหมดเท่านั้น
Konrad Morawski

3
@KonradMorawski วัตถุทั้งหมดที่ไม่ถูกต้องหมายถึงการถ่ายโอนข้อมูลแบบวนซ้ำของวัตถุไม่ใช่ว่าจะรวมถึงเขตข้อมูลซึ่งสามารถนำไปสู่การวนซ้ำแบบไม่สิ้นสุดได้อย่างง่ายดาย คุณไม่ควรคิดว่าคนอื่นกำลังพูดถึงอะไร คำตอบของฉันทั้งเกี่ยวข้องและเป็นประโยชน์การโหวต + ความคิดเห็นของคุณไม่เป็นเช่นนั้น
Mythz

1
@mythz ใช่แน่นอนคุณต้องป้องกันไม่ให้สแต็กล้น (เช่นทุกInt32ฟิลด์มีMaxValueฟิลด์ซึ่งก็คือInt32ตัวมันเอง ... ) นั่นเป็นจุดที่ดี แต่มันไม่ได้เปลี่ยนความจริงที่ว่าอ็อบเจกต์ - - ประกอบด้วยฟิลด์ด้วยไม่ใช่แค่คุณสมบัติ มีอะไรเพิ่มเติม (คุณไม่ได้อยู่ที่หนึ่ง) ? objectnameในImmediate Window ไม่ช่องแสดง - ไม่เรียกวง จำกัด หากนั่นเกี่ยวกับการลงคะแนนของฉันฉันสามารถถอนได้ (ถ้าคุณให้ฉันปลดล็อคนั่นคือ) ฉันไม่เห็นด้วยในหลักการอยู่แล้ว
Konrad Morawski

4
-1 สำหรับคำตอบที่เชื่อมโยงเท่านั้นแม้ว่าจะดูดีถ้าฉันสามารถใช้มันได้! บางทีฉันอาจจะตาบอด แต่หาแหล่งที่มาจากลิงค์นั้นไม่ได้ โฟลเดอร์อัปโหลดทั้งสองว่างเปล่า รหัสยาวเกินไปที่จะรวมไว้ในคำตอบหรือไม่

14

นี่เป็นวิธีง่ายๆในการเขียนวัตถุแบน ๆ ที่มีรูปแบบสวยงาม:

using Newtonsoft.Json.Linq;

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

สิ่งที่เกิดขึ้นคือการที่วัตถุถูกแปลงแรกที่จะเป็นตัวแทนภายใน JSON โดยJObject.FromObjectและแปลงเป็นสตริง JSON ToStringแล้ว (และแน่นอนว่าสตริง JSON เป็นตัวแทนที่ดีมากของออบเจ็กต์ธรรมดาโดยเฉพาะอย่างยิ่งเนื่องจากToStringจะมีการขึ้นบรรทัดใหม่และการเยื้อง) แน่นอนว่า "ToString" นั้นไม่เกี่ยวข้อง (เนื่องจากโดยนัยโดยใช้+เพื่อต่อสตริงและอ็อบเจ็กต์) แต่ ฉันชอบที่จะระบุไว้ที่นี่


5
JsonConvert.SerializeObject (ชื่นชมจัดรูปแบบอินเทรนด์) เพื่อการอ่านที่สะดวกสบายในบันทึก
Tertium

1
HotLicks - ฉันอยากจะบอกให้คุณทราบว่าการมีส่วนร่วมนี้มีความสำคัญกับฉันแค่ไหนในตอนนี้ ฉันมีความต้องการที่จะตรวจสอบสิ่งที่เปลี่ยนแปลงในระหว่างการอัปเดตและคุณเพิ่งลดความเครียดจากระดับ 'ตื่นตระหนก' กลับลงมาสู่ระดับ 'กังวล' ที่จัดการได้ ขอบคุณครับขอให้คุณมีชีวิตที่ยืนยาวและมีความสุข
Iofacture

4

คุณสามารถใช้การสะท้อนและวนซ้ำคุณสมบัติของวัตถุทั้งหมดจากนั้นรับค่าและบันทึกลงในบันทึก การจัดรูปแบบเป็นเรื่องเล็กน้อย (คุณสามารถใช้ \ t เพื่อเยื้องคุณสมบัติของวัตถุและค่าของวัตถุ):

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

4

สิ่งที่ฉันชอบทำคือการลบล้าง ToString () เพื่อให้ฉันได้ผลลัพธ์ที่มีประโยชน์มากกว่าชื่อประเภท สิ่งนี้มีประโยชน์ในการดีบักเกอร์คุณสามารถดูข้อมูลที่คุณต้องการเกี่ยวกับวัตถุโดยไม่จำเป็นต้องขยาย


3

ฉันพบไลบรารีชื่อObjectPrinterซึ่งอนุญาตให้ถ่ายโอนวัตถุและคอลเล็กชันไปยังสตริง (และอื่น ๆ ) ได้อย่างง่ายดาย มันทำในสิ่งที่ฉันต้องการ


3

ต่อไปนี้เป็นเวอร์ชันอื่นที่ทำสิ่งเดียวกัน (และจัดการคุณสมบัติที่ซ้อนกัน) ซึ่งฉันคิดว่าง่ายกว่า (ไม่มีการพึ่งพาไลบรารีภายนอกและสามารถแก้ไขได้อย่างง่ายดายเพื่อทำสิ่งอื่นนอกเหนือจากการบันทึก):

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
นี่จะตายอย่างน่าสยดสยองหากคุณมีDateทรัพย์สินอยู่ภายในของคุณ ... แค่บอกว่า ...
Noctis

2

คุณสามารถเขียนวิธี 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และตรวจสอบอินเทอร์เฟซแอตทริบิวต์ประเภทฐาน ฯลฯ และการเรียกซ้ำ (เนื่องจากเป็นวิธีการเรียกซ้ำ) ด้วยวิธีนี้เราอาจได้รับวัตถุทิ้ง แต่มันน่าเบื่ออย่างแน่นอน การใช้รถเททิ้งวัตถุจากตัวอย่าง LINQ ของ Microsoft จะช่วยประหยัดเวลาของคุณ


จากความอยากรู้อยากเห็น: สิ่งนี้จัดการอาร์เรย์หรือรายการอย่างไร? หรือคุณสมบัติที่อ้างอิงอ็อบเจ็กต์พาเรนต์?
Dan Esparza

@DanEsparza ขอบคุณที่แสดงวิธีที่เฉพาะเจาะจงมากขึ้น
Ariful Islam

2

จากคำตอบของ @engineforce ฉันสร้างคลาสนี้ที่ฉันใช้ในโครงการ PCL ของ Xamarin Solution:

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

เส้นทางทั้งหมดข้างต้นถือว่าออบเจ็กต์ของคุณสามารถต่ออนุกรมกับ XML หรือ JSON ได้
หรือคุณต้องใช้โซลูชันของคุณเอง

แต่สุดท้ายคุณก็ยังไปถึงจุดที่คุณต้องแก้ปัญหาเช่น

  • การเรียกซ้ำในวัตถุ
  • วัตถุที่ไม่ต่ออนุกรมได้
  • ข้อยกเว้น
  • ...

บวกบันทึกที่คุณต้องการข้อมูลเพิ่มเติม:

  • เมื่อเหตุการณ์เกิดขึ้น
  • callstack
  • ซึ่ง threead
  • สิ่งที่อยู่ในเซสชันของเว็บ
  • ที่อยู่ IP ใด
  • URL
  • ...

มีทางออกที่ดีที่สุดที่จะแก้ปัญหาทั้งหมดนี้และอื่น ๆ อีกมากมาย
ใช้แพคเกจนี้ Nuget: Desharp
สำหรับทุกประเภทของการใช้งาน - ทั้งเว็บและการใช้งานเดสก์ทอป
ดูมันเอกสาร 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
  • สามารถบันทึกล็อกใน HTML ที่ดี (หรือในรูปแบบ TEXT กำหนดค่าได้)
  • เป็นไปได้ที่จะเขียนตัวเลือกในเธรดพื้นหลัง (กำหนดค่าได้)
  • มีตัวเลือกสำหรับความลึกสูงสุดของวัตถุและความยาวสตริงสูงสุด (กำหนดค่าได้)
  • จะใช้ลูปสำหรับวัตถุ iteratable และการสะท้อนย้อนหลังทุกอย่างอื่น
    แน่นอนสำหรับสิ่งที่คุณจะพบในสภาพแวดล้อม .NET

ฉันเชื่อว่ามันจะช่วยได้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.