views:

106

answers:

3

Hi Guys

Suppose I am watching something in VS2008 and I want to search the object I'm watching for an instance of a particular value.

For example, say I'm watching this and I want to search for a control called mycontrol inside it or I want to search for a string that currently has the value of "Hello World".

I know it's kind of a brute force way of doing things, but I find it would be a quick way of identifying where things are going wrong whilst debugging. Warning: I'm about to swear... When I was using PHP, I could see all variables that were currently set by using get_defined_vars(). It was dirty, but it was quick and I'd like to know if there's something similar I can do in VS.

Sorry if I've been a little vague, I'd be happy to elaborate if you have questions.

Cheers Iain

Edit: What I'm actually tring to do is interrogate the current state of the application and quickly search for the various classes that I want to debug. What I'm doing is trying to debug where I don't have the source code (I'm writing a control for a CMS). So I know what the value of something should be, but I don't know where in the structure it exists - that's what I want to find.

e.g. An exeption is thrown by the application because foo should be a list of the type bar. I want to find out where foo is defined so I can look around and see what the other variables in the same class are set to.

Sorry again, I'm finding it hard to explain :(

Edit #2: I find a good tree might help me visualise it better...

Quickwatch
-this
 -var1
   +var1a
   +var1b
   -var1c
    -base
     -foo = "Hello World"
    +var1ca
 +var2
 +var3

In the above, how would I quickly drill down through the structure to find foo?

+2  A: 

It sounds like you want a conditional breakpoint:

When the breakpoint location is reached, the expression is evaluated and the breakpoint is hit only if the expression is true or has changed.

Create a new breakpoint, right-click on it, and select "Condition..." Enter the condition you'd like to wait for. It'll be something like:

this.MyString == "Hello World"

EDIT: Ok, I understand now you want to interrogate another, running application. Assuming it was built in a managed language, you may be interested in Hawkeye:

Hawkeye is the only .Net tool that allows you to view, edit, analyze and invoke (almost) any object from a .Net application. Whenever you try to debug, test, change or understand an application, Hawkeye can help.

Free. Not been updated in a while.

Michael Petrotta
Thanks for your answer Michael. Unfortunately this isn't what I'm trying to acheive. I've added more detail to my question if this helps :)
Iain Fraser
+1! Hey, Hawkeye looks awesome, I'll try that for sure. But I should have told you before, I'm actually working with ASP.NET application (i.e. a website) so there's nothing for me to drag the pointer on to as such. :)
Iain Fraser
Try pointing at the iis process. It is debuggable (thats how you can debug asp.net applications)
Gregory
A: 

It sounds like you are envisioning a feature which would descend down the tree presented in the debugger UI looking for a typed in value. This is not a feature of the debugger at this time (although at first glance it sounds handy). It would have problems though in cases where the expression had infinite expansions.

Circular references for instance will cause an infinite expansion. Those are fairly easy to track down but there are more nefarious tricks which can be done to make infinite expansion harder / impossible to track. True we could probably control for depth and such ...

I think your best bet is to write a reflection based searching mechanism with a depth control mechanism. Then call this API from the debugger window.

JaredPar
+1  A: 

I wrote this the other day. It did the job well enough (however it is only some utility code for debugging, so use at your own risk --> the design is pretty bad >_< ). Dumps out the fields and iterates downwards. It might not be perfect, but it solved my problem at the time.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

public static class Dumper
{
    public class Dump
    {
        public Dump(bool spacesInsteadOfTab)
        {
            _spacesIndeadOfTab = spacesInsteadOfTab;
        }

        private readonly StringBuilder _sb = new StringBuilder();

        public string Result
        {
            get
            {
                return _sb.ToString();
            }
        }

        private readonly bool _spacesIndeadOfTab;

        private int _currentIndent;
        public int CurrentIndent
        {
            get
            {
                return _currentIndent;
            }
            set
            {
                _currentIndent = value > 0 ? value : 0;
            }
        }

        public void IncrementIndent()
        {
            CurrentIndent += 1;
        }

        public void DecrementIndent()
        {
            CurrentIndent -= 1;
        }

        private void AppendIndent()
        {
            if (_spacesIndeadOfTab)
                _sb.Append(' ', _currentIndent * 4);
            else
                _sb.Append('\t', _currentIndent);
        }

        public void Log(string logValue)
        {
            AppendIndent();
            _sb.AppendLine(logValue);
        }

        public void Log(string logValue, params object[] args)
        {
            AppendIndent();
            _sb.AppendFormat(logValue, args);
            _sb.AppendLine();
        }
    }

    public static Dump TakeDump(object objectToDump, int maxDepth)
    {
        Dump result = new Dump(false);

        int currentDepth = 0;

        TakeDump(ref result, ref currentDepth, maxDepth, objectToDump);

        return result;
    }

    private static void TakeDump(ref Dump result, ref int currentDepth, int maxDepth, object objectToDump)
    {
        currentDepth++;
        if (currentDepth > maxDepth)
        {
            result.IncrementIndent();
            result.Log("MaxDepth ({0}) Reached.", maxDepth);
            result.DecrementIndent();
            return;
        }

        var objectType = objectToDump.GetType();
        result.Log("--> {0}", objectType.FullName);

        result.IncrementIndent();
        var fields = objectType.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

        if (fields.Count() == 0)
            result.Log("No fields");

        foreach (var fieldInfo in fields)
        {
            var fieldValue = fieldInfo.GetValue(objectToDump);

            if (fieldValue == null)
                result.Log("{0} is null", fieldValueType.FullName, fieldInfo.Name);

            var fieldValueType = fieldValue.GetType();

            if (fieldValueType.IsValueType)
                result.Log("{2} as {0} (ToString: {1})", fieldValueType.FullName, fieldValue.ToString(), fieldInfo.Name);
            else
                TakeDump(ref result, ref currentDepth, maxDepth, fieldValue);
        }
        result.DecrementIndent();
    }
}
Gregory
Thanks Gregory. This tool comes closest to answering my question and given that VS doesn't seem to have this functionality, I may just try doing this myself. Gotta love helper classes :) Well done
Iain Fraser