Home

Dump only part of an Object

Hello together;

Does anybody know how to dump only a part of an object ?
I have Objects to dump but i dont want to see a certain column.
All objects to Dump differ from each other but all have one column with the same name i dont want to display.

Can someone help me with it?

thanks in advance

Klaus

Comments

  • Are you dumping to data-grids or rich text, and are the objects your own custom types? If rich text and they are your custom types, you could make use of ICustomMemberProvider - see https://www.linqpad.net/FAQ.aspx#extensibility
  • Thanks for your answer kingkeith;

    I am dumping to richtext (html).
    Unfortunately the type is not my own custom type,
    therefore your idea does'nt fit for my problem.

    But anyway, thanks a lot.

    klaus
  • This would be possible if the static .Dump() method accept a membersToInclude array like Util.WriteCsv() does.
    var source = new[] {
      new { FirstName = "Foo", SurName = "Bar", Password = "secret" },
    };
    
    var membersToInclude =
      source
        .First()
        .GetType()
        .GetProperties()
        .Where(x => x.Name != "Password")
        .Select(x => x.Name)
        .ToArray();
    
    Util.WriteCsv(source, @"C:\Temp\test.csv", membersToInclude);
    Output:
    FirstName,SurName
    Foo,Bar
    Unfortunately this is not the case.

    Instead of hiding the entire column, you could wipe the contents of each row by setting the value to null (if applicable) in a loop:
    
    // Hide password
    foreach (dynamic item in source)
    {
      item.Password = null;
    }
    
  • How about a Dump() method accepting a lambda? It would dump the result of the expression, but return the original object. It could be good to inspect intermediate results.

    .Where(t=>t.Something)
    .Dump(t=>t.Count(),"Count after first Where")
    .Where(t=>t.SomeOtherThing)
    .Dump(t=>t.Contains(MyObject),"MyObject still present after second Where")
    .Where(t=>t.OhAnotherThing)

    Can of course be done with helper methods.
  • Yeah, you can add something like this to your own MyExtensions:
        public static IEnumerable<T> Dump<T, U>(this IEnumerable<T> obj, Func<T, U> DumpThis, string description = null)
        {
            if (description != null)
            { obj.Select(DumpThis).Dump(description); }
            else
            { obj.Select(DumpThis).Dump(); }
            return obj;
        }
  • edited November 2015
    I've added a feature to the new beta to make this possible.

    The Dump extension method now has an optional parameter for specifying a comma-delimited list of columns/members to exclude from the output. For example:

    Customers.Dump (exclude:"ID, Purchases");

    This feature works in both rich-text and datagrid mode.

    http://www.linqpad.net/download.aspx#beta
  • Hello Joe;

    Thanks a lot for fulfilling me wish.
    That helps me very much

    Have a good time;
    klaus
  • The text exclude is nice, because it can be used in the MyExtensions file. Can you include an include as well that acts as a whitelist? It's often easier to list the things you want dumped rather then the things you don't want dumped. When you want 2 properties displayed, and you are dealing with 20 properties for example.
  • edited November 2015
    I started out with an "include" option, but took it out because of the potential confusion with Entity Framework's "Include". I'd have to deal with bug reports where someone puts "Customer.Orders" into their "include", and wonders why it round-trips to the database. Also, in most cases you can achieve the desired result with an anonymous type.
  • Well the main reason I would use this new dump feature is to maintain my ability to edit the thing being dumped, otherwise I would just use select. If include has a naming conflict, perhaps you could use the word whitelist, with, or you could make exclude more powerful Ex: "exclude:"*,!Id,!Name"); //Exclude everything except id, and name
  • edited November 2015
    I guess another option would be a format string, something like:

    Dump (xyz, format: "-ID, -Name") // exclude id and name

    or

    Dump (xyz, format:"+ID, +Name") // include id and name

    It might be more confusing and less discoverable, though.
  • edited November 2015
    I suppose then you'd also expect the following to work:

    Dump (xyz, format:"ID:999")

    Would that include *only* the ID column, or merely specify the desired format string for that column?
  • You could add another overload like this "columns:"Id, Name"
  • Except that the 'columns' overload would have the same signature as the 'exclude' overload.
  • edited November 2015
    Good point.
    Here are some other ideas that might work

    string columns = Util.DumpColumns(Persons,exclude:"Id,Name");
    Persons.Dump(exclude:columns);

    DumpSettings settings = new DumpSettings{
    Include="Id,Name",
    Format="Id:999"
    };
    Persons.Dump(settings);

    Persons.Dump(x=>new{x.Id,x.Name});

    Persons.Dump(exclude:"*,-Id,-Name");
  • edited November 2015
    I'd vote for the Dump(Func<TInput, TOutput> selector) override as proposed by @Tormod and @markhurd
  • I just found the exclude alternative, but it only works for the first level object as far as I can see?

    Is there a way to get it to exclude recursively?

    I am regularly dumping AST trees which can get very large and containing many irrelevant properties.

    For example, excluding all location/position properties.



  • edited August 2016
    To extend dmartensson, I also notice that exclude has trouble with nested objects. But for me it wouldn't work at all, top level or not. Unfortunately, due to their complexity, nested objects are when I tend to need something like exclude.

    Could a possible approach be to create a new interface like ICustomMemberProvider, but with a property that is ultimately set by an exclude or similar parameter inside .Dump()? This way the string can be processed by the user as he/she desires.
  • edited August 2016
    From LINQPad 5.08, you can define a "ToDump" method on any class, which controls how the object is dumped. This is a convention-based system, so you do not need to reference LINQPad.exe.

    For instance:
    class Foo
    {
      public string Firstname, LastName, Junk
      object ToDump() => new { FirstName, LastName }
    }
    For a more dynamic approach, create an ExpandoObject:
    object ToDump()
    {
        IDictionary<string, object> expando = new System.Dynamic.ExpandoObject();
    
        string someColumnName = "Column1";
        expando [someColumnName] = "foo";
        
        return expando;
    }
    The following dumps all properties except for those of type "XYZ":
    object ToDump()
    {
        IDictionary<string, object> expando = new System.Dynamic.ExpandoObject();
    
        foreach (var prop in GetType().GetProperties (BindingFlags.Public | BindingFlags.Instance))
            if (prop.GetIndexParameters().Length == 0 &&
                prop.PropertyType.FullName != "XYZ")
                try
                {
                    expando.Add (prop.Name, prop.GetValue (this));
                }
                catch (Exception ex)
                {
                    expando.Add (prop.Name, ex);
                }
    
        return expando;
    }
  • I gave it a try in one area of my project. It's beautiful.

    As for my request to be able to pass parameters inside Dump() to ICustomMemberProvider, this would convert to a request to have ToDump take parameters passed via Dump(). But I see now that this isn't necessary, as I can just create fields or properties inside a class and reference them from ToDump to change the output behavior.

    Thank you!
  • do any of these options that don't require manually writing out a whitelisted type or anonymous object work on IEnumerables?

    seems that the built-in .Dump(exclude:"propName") doesn't care about properties on the things inside an IEnumerable at all.
  • edited November 2016
    Playing around with IEnumerables and extending Dump to exclude some fields of anonymous objects, I created:
    private static Dictionary<string, object> ToDictionary(object item) { var eitem = new Dictionary<string, object>(); foreach (var prop in item.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)) { if (prop.GetIndexParameters().Length == 0) try { eitem.Add(prop.Name, prop.GetValue(item)); } catch (Exception ex) { eitem.Add(prop.Name, ex); } } return eitem; }
    public static ExpandoObject ToExpando(this IDictionary<string, object> d) { var e = new ExpandoObject(); var di = (IDictionary<string, object>)e; foreach (var kvp in d) di.Add(kvp); return e; }
    public static IDictionary<TKey, TValue> Remove<TKey, TValue>(this IDictionary<TKey, TValue> d, TKey[] except) { foreach (var e in except) d.Remove(e); return d; }
    public static IEnumerable<ExpandoObject> ToEnumExpando<T>(this IEnumerable<T> obj, string[] except = null) { return obj.Select(item => ToDictionary(item).Remove(except).ToExpando()); }
    public static IEnumerable<T> Dump<T>(this IEnumerable<T> obj, string[] except, string descr = null) { var enumitems = obj.ToEnumExpando(except); if (descr != null) enumitems.Dump(descr); else enumitems.Dump(); return obj; }

    It takes a string[] of fields to exclude to avoid conflicting with existing Dump() definitions. I have another version that creates an anonymous object instead of using the Expando, but it has a bit more code.

    PS Sorry about the code formatting, couldn't figure out what the block expected.
Sign In or Register to comment.