Tüm nesneleri C # 'daki bir günlüğe dökmenin en iyi yolu nedir?


129

Bu nedenle, çalışma zamanında geçerli bir nesnenin durumunu görüntülemek için, Visual Studio Immediate penceresinin bana verdiği şeyi gerçekten seviyorum. Sadece basit yapıyorum

? objectname

Bana nesnenin güzel biçimlendirilmiş bir "dökümünü" verecek.

Bunu kodda yapmanın kolay bir yolu var mı, böylece oturum açarken benzer bir şey yapabilir miyim?


Sonunda, T.Dump'ı biraz kullandım. Oldukça sağlam bir çözüm - sadece özyinelemeye dikkat etmeniz gerekiyor.
Dan Esparza

Bu eski bir sorudur, ancak birçok arama sonuçlarının başında gelir. Gelecekteki okuyucular için: Bu vs uzantısına bakın . VS2015'te benim için harika çalıştı.
Jesse Good

1
Bu VS eklentisi korunmadığından ve bazı özelliklerden yoksun olduğundan 2020 için güncelleme. Aşağıdaki kitaplık kodda da aynı şeyi yapar - ve birkaç ekstra özelliği vardır, örneğin döngülerden kaçınmak için daha önce nerede ziyaret edildiğini izler: github.com/thomasgalliker/ObjectDumper
Nick Westgate

Yanıtlar:


55

Linq örnekleriyle birlikte gönderilen ObjectDumper koduna bir şey dayandırabilirsiniz . Bir örnek almak için
bu ilgili sorunun cevabına da bir göz atın .


5
Ayrıca diziler için de çalışmaz (yalnızca dizinin türünü ve uzunluğunu görüntüler, ancak içeriğini yazdırmaz).
Konrad Morawski

5
ObjectDumper için nuget paketi artık mevcut. Aynı zamanda, bir uzantısı bir yöntem sağlar DumpToStringve Dumpiçin Objectsınıf. Kullanışlı.
IsmailS

2
w3wp.exeObjectDumpergibi kullanmaya çalıştığımda çöküyorRequest.DumpToString("aaa");
Paul

60

Daha büyük bir nesne grafiği için, Json kullanımını tercih ediyorum, ancak biraz farklı bir stratejiyle. İlk olarak, çağrılması kolay ve Json dönüşümünü saran statik bir yöntemle (not: bunu bir uzantı yöntemi yapabilir) statik bir sınıfım var.

using Newtonsoft.Json;

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

Sonra senin Immediate Windowiçinde

var lookHere = F.Dump(myobj);

lookHere, Localsbaşına $ ile eklenen pencerede otomatik olarak görünür veya ona bir saat ekleyebilirsiniz. Denetçideki Valuesütunun sağ tarafında, yanında açılır bir imleç bulunan bir büyüteç vardır. Açılır imleci seçin ve Json görselleştiriciyi seçin.

Screenshot of Visual Studio 2013 Locals window

Visual Studio 2013 kullanıyorum.


2
SerializeObj -> SerializeObject?
Wiseman

Harika, teşekkürler. Uzak sunucuma Visual Studio için hata ayıklama araçları yükleyemiyorum ve bu şey asp.net mvc uygulamamda son derece iyi çalışıyor.
Liam Kernighan

1
Güzel biçimlendirme için şunları yapabilirsiniz:Newtonsoft.Json.JsonConvert.SerializeObject(sampleData, Formatting.Indented)
Zorgarath

elle yapmaya çalışmaktan çok daha kolay. Karmaşıklaşıyor
ahong

26

Bunu yapmanın daha iyi yolları olduğundan eminim, ancak geçmişte bir nesneyi günlüğe kaydedebileceğim bir dizeye serileştirmek için aşağıdaki gibi bir yöntem kullandım:

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

Yöntemin, serileştirilmiş nesne yerine istisnayı da döndürebileceğini göreceksiniz, bu nedenle günlüğe kaydetmek istediğiniz nesnelerin serileştirilebilir olduğundan emin olmak isteyeceksiniz.


2
Soruyu yanıtladıktan sonra C # 'a eklenen özellikler ışığında, bu uygulamanın bir genişletme yöntemi olarak iyi çalıştığını belirtmek faydalı olabilir. Object sınıfına uygulanırsa ve ihtiyacınız olan her yerde uzantıya başvurursanız, işlevi çağırmanın uygun bir yolu olabilir.
Nikita G.

Bu işten almaya devam: Failed to access type 'System.__ComObject' failed. Noob to c #, yardım için minnettar olur.
GuySoft

1
@GuySoft Nesnenizdeki özelliklerden birinin veya nesnenin kendisinin serileştirilebilir olmadığından şüpheleniyorum.
Bernhard Hofmann

Bu yöntemi maalesef parametresiz bir kurucu olmadan sınıflarda kullanamazsınız. Serileştirilemezler.
Jarekczek

22

Visual Studio Hemen Penceresini kullanabilirsiniz

Sadece bunu yapıştırın ( actualaçıkça nesne adınıza değiştirin ):

Newtonsoft.Json.JsonConvert.SerializeObject(actual);

Nesneyi JSON'da yazdırmalıdır görüntü açıklamasını buraya girin

Bunu textmechanic text tool veya notepad ++ üzerine kopyalayıp kaçan tırnakları ( \") ile "ve satırsonlarını ( \r\n) boş alanla değiştirebilmeniz, ardından çift tırnak işaretlerini ( ") baştan ve sondan kaldırıp jsbeautifier'a yapıştırarak daha okunaklı hale getirebilmelisiniz.

OP'nin yorumuna GÜNCELLE

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

bu, herhangi bir nesneyi atmanıza izin vermelidir.

Umarım bu size biraz zaman kazandırır.


Teşekkürler. Belki ilk sorumda anlamadınız, ancak hemen pencereyi zaten bildiğimi ve uygulamamda oturum açarken aynı şeyi yapmak istediğimi belirttim.
Dan Esparza

@DanEsparza Console.Log(Newtonsoft.Json.JsonConvert.SerializeObject(actual));? :) ve evet gerçekten kaçırdım. Bu soru google.co.uk/… 'de
Matas Vaitkevicius

2
Bilginize, bir C # dizesinde bir JSON dizeniz olduğunda, dizenin sağındaki spyglass simgesine tıklayın ve Metin Görselleştiriciyi seçin. JSON dizesinin düz metin versiyonunu gösteren bir pencere açacaktır (çıkış karakterli tırnaklar veya \ r \ n değil).
Walter

17

ServiceStack.Text , tam olarak bunu yapan bir T.Dump () genişletme yöntemine sahiptir, her türden tüm özellikleri güzel okunabilir bir biçimde özyinelemeli olarak döker.

Örnek kullanım:

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

ve çıktı:

{
    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
Tarlalar için çalışmıyor. OP açıkça "tüm nesneler" hakkında sorular soruyordu.
Konrad Morawski

5
He didn't say fields- entire objectsalanları içeren dedi . Ayrıca, başarmak istediği şeyi örnek olarak Visual Studio'nun Anında Pencere özelliğinden de bahsetti ( "Sadece basit bir şey yapmak ? objectname, nesnenin güzel bir şekilde biçimlendirilmiş bir" dökümünü "verecektir" ). ? objectnametüm alanları da yazdırır. This has been immensely helpful - one of my most used extension methods to date- Yararlı olup olmadığını sorgulamıyorum, sadece tüm nesneleri attığını.
Konrad Morawski

3
@KonradMorawski Nesnelerin tamamının yanlış olması, nesnenin özyinelemeli bir dökümü anlamına gelir, alanları içermesi DEĞİL, sonsuz özyinelemeli döngüye neden olabilir. Başkalarının ima ettiklerini varsaymamalısınız. Cevabım hem alakalı hem de yararlı, sizin olumsuz oyunuz + yorumunuz değil.
mystz

1
@mythz evet, elbette bir yığın taşmasını önlemeniz gerekir (örneğin, her Int32alanın bir MaxValuealanı vardır, bu da Int32kendi başına ...), bu iyi bir nokta, ancak nesnelerin ve kesinlikle tüm nesnelerin olduğu gerçeğini değiştirmez - sadece özelliklerden değil, alanlardan da oluşur. Dahası, sonsuz bir döngüyü tetiklemeden ? objectname, Immediate Window yok görüntüleme alanlarında (bunu ele almadınız). Bu benim olumsuz oyumla ilgiliyse, geri alabilirim (eğer kilidi açarak bana izin verirseniz, yani). Yine de prensipte katılmıyorum.
Konrad Morawski

4
-1 esasen yalnızca bağlantı içeren bir yanıt için, ancak kullanabilirsem harika görünüyor! Belki körüm ama bu bağlantı üzerinden kaynak bulamıyorum; iki yükleme klasörü boş. Kod cevaba eklenemeyecek kadar uzun mu?

14

İşte güzel biçimlendirilmiş düz bir nesne yazmanın aptalca basit bir yolu:

using Newtonsoft.Json.Linq;

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

Olan şey, nesnenin önce tarafından bir JSON dahili temsiline JObject.FromObjectdönüştürülmesi ve ardından ToString. (Ve elbette bir JSON dizesi, basit bir nesnenin çok güzel bir temsilidir, özellikle ToStringde satırsonları ve girintiler içereceği için.) "ToString" elbette gereksizdir ( +bir dizeyi ve bir nesneyi birleştirmek için kullanılmasıyla ima edildiği gibi ), ancak Burada belirtmek isterim.


5
Günlükte rahat okuma için JsonConvert.SerializeObject (apprec, Formatting.Indented)
Tertium

1
HotLicks - Size şu anda bu katkının benim için ne kadar önemli olduğunu iletmek istiyorum. Güncelleme sırasında nelerin değiştiğini denetlemem gerekiyor ve stresimi 'panik' seviyesinden yönetilebilir bir 'endişe' seviyesine düşürdünüz. Teşekkür ederim efendim, çok uzun ve kutsanmış bir hayatınız olabilir mi
Iofacture

4

Tüm nesne özelliklerinde yansıma ve döngü kullanabilir, ardından değerlerini alabilir ve günlüğe kaydedebilirsiniz. Biçimlendirme gerçekten önemsizdir (bir nesnenin özelliklerini ve değerlerini girintilemek için \ t kullanabilirsiniz):

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

4

Yapmaktan hoşlandığım şey ToString () 'i geçersiz kılmaktır, böylece tür adının ötesinde daha kullanışlı çıktılar elde ederim. Bu, hata ayıklayıcıda kullanışlıdır, bir nesne hakkında istediğiniz bilgileri, onu genişletmeye gerek kalmadan görebilirsiniz.



3

Aşağıda, aynı şeyi yapan (ve iç içe geçmiş özellikleri işleyen) başka bir sürüm daha basit olduğunu düşünüyorum (harici kitaplıklara bağımlılık yoktur ve günlük kaydı dışında başka şeyler yapmak için kolayca değiştirilebilir):

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
Dateiçsel nesnenizde bir özelliğiniz varsa bu korkunç bir şekilde ölecek ... sadece söylüyorum ...
Noctis

2

Kendi WriteLine yönteminizi yazabilirsiniz.

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

Gibi kullanın-

WriteLine(myObject);

Bir koleksiyon yazmak için kullanabileceğimiz-

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

Yöntem şöyle görünebilir:

 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 ifArayüzleri, öznitelikleri, temel türü vb. Kullanmak ve kontrol etmek ve özyinelemeyi (bu özyinelemeli bir yöntem olduğundan) bu şekilde bir nesne dökümü elde edebiliriz, ancak bu kesinlikle sıkıcıdır. Microsoft'un LINQ Örneğindeki nesne damperini kullanmak zamandan tasarruf etmenizi sağlar.


Meraktan: Bu, dizileri veya listeleri nasıl ele alıyor? Veya ana nesnelere başvuran özellikler?
Dan Esparza

@DanEsparza Bana daha spesifik olmanın yolunu gösterdiğin için teşekkürler.
Ariful Islam

2

@Engineforce cevabına dayanarak, Xamarin Çözümünün bir PCL projesinde kullandığım bu sınıfı yaptım:

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

Yukarıdaki yolların tümü, nesnelerinizin XML veya JSON'a serileştirilebilir olduğunu veya
kendi çözümünüzü uygulamanız gerektiğini varsayar .

Ama sonunda yine de şu gibi sorunları çözmeniz gereken noktaya gelirsiniz:

  • nesnelerde özyineleme
  • serileştirilemez nesneler
  • istisnalar
  • ...

Artı daha fazla bilgi istediğiniz günlüğü:

  • olay ne zaman oldu
  • çağrı yığını
  • hangi üç
  • web oturumunda ne vardı
  • hangi ip adresi
  • uRL
  • ...

Tüm bunları ve daha fazlasını çözen en iyi çözüm var.
Şu Nuget paketini kullanın: Desharp .
Tüm uygulama türleri için - hem web hem de masaüstü uygulamaları .
'S Bkz Desharp Github belgelerine . It has birçok konfigürasyon seçenekleri .

İstediğiniz yeri arayın:

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
  • günlüğü güzel HTML olarak (veya yapılandırılabilir METİN biçiminde) kaydedebilir
  • isteğe bağlı olarak arka planda yazılabilir (yapılandırılabilir)
  • maksimum nesne derinliği ve maksimum dizi uzunluğu için seçeneklere sahiptir (yapılandırılabilir)
  • Yinelenebilir nesneler için döngüler ve diğer her şey için geriye doğru yansıma kullanır,
    gerçekten de .NET ortamında bulabileceğiniz her şey için .

Yardımcı olacağına inanıyorum.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.