Uniquely Identifying Reference Types in the Debugger

Uniquely Identifying Reference Types in the Debugger

What you're looking for are object id's. For any referenc type in the debugger you can right click and say "Make Object ID". This will add a # suffix to the value column whenever that instance is displayed in the debugger. You can also add #1, #2, etc ... to the watch window to see them again any time later.

Step 0 - Run this code

static void Main(string[] args)
{
var x = "a string";
var y = x;
System.Diagnostics.Debugger.Break();
}

Step 1 - Right Click and select "Make Object Id"

alt text

Step 2 - Instances now display with the 1# suffix. Note: I did nothing special in this step. Immediately after clicking "Make Object Id" both rows updated to display the 1# suffix since they refer to the same instance.

alt text

Step 3 - See them at any time by adding 1# to the watch window

alt text

When debugging, is there a way to tell if an object is a different instance?

When debugging, in the Locals window, right-click on the instance and select "Make Object ID".

This will add number that is unique for this instance which is displayed whenever you see this
instance in the debugger (in tool-tips as well as in the watch window).

enter image description here

enter image description here

How to identify different instance of object?

If your question is how to tell which reference you are looking at in an instance method, you can add this to your watch list, and then right click on the watch list entry and select "Make Object ID" which will tag the reference with a unique ID.

Follow the steps in this similar SO question: Identifying Unique References in Debugger

If your question is how to tell if two references are the same, you can use ReferenceEquals() to compare them (or == if you know it hasn't been overloaded for the type).

In Visual Studio, can I set conditional breakpoints that can peek variables from another scope?

If it is possible to change the code, the less interfering code that I can imagine is the following - without using the trick of the hits count of @Maaz.

It is based on using the current thread to "storage" the values.

void F1() {
for (int i = 0; i < 100; i ++)
{
CallContext<Int32>.SetData("i-first", i);
F2();
}
}

void F2() {
for (int i = 0; i < 100; i ++)
{
CallContext<Int32>.SetData("i-second", i);
F3();
}
}

void F3() {
int a = 0; // break point here
for (int i = 0; i < 100; i ++)
a ++;
}

//Helper class for .Net Core.
//For .Net Framework you can use CallContext.LogicalSetData, CallContext.LogicalGetData
public static class CallContext<T>
{
static ConcurrentDictionary<string, AsyncLocal<T>> state =
new ConcurrentDictionary<string, AsyncLocal<T>>();

public static void SetData(string name, T data) =>
state.GetOrAdd(name, _ => new AsyncLocal<T>()).Value = data;

public static T GetData(string name) =>
state.TryGetValue(name, out AsyncLocal<T> data) ? data.Value : default(T);
}

The conditional expression for the breakpoint is:

CallContext<Int32>.GetData("i-first") == 70 && CallContext<Int32>.GetData("i-second") == 80

Any way to show/compare object references in watch window?

There is actually a built in feature for comparing objects in the Watch window that doesn't require you to call any functions directly. It's in the right click menu as "Make Object ID"

Make Object ID

It will mark the object with an ID, and then you can add a second object and mark it with an id as well. If those object are the same reference, then they will have the same ID. This allows you to see if/when they change as you are debugging.

.NET unique object identifier

The reference is the unique identifier for the object. I don't know of any way of converting this into anything like a string etc. The value of the reference will change during compaction (as you've seen), but every previous value A will be changed to value B, so as far as safe code is concerned it's still a unique ID.

If the objects involved are under your control, you could create a mapping using weak references (to avoid preventing garbage collection) from a reference to an ID of your choosing (GUID, integer, whatever). That would add a certain amount of overhead and complexity, however.

Uniquely identifying a method or constructor using reflection

Including Stefan's suggestions, you could define an extension method class like this one:

public static class CustomReflectionHelpers
{
public static String CreateUniqueName(this MethodInfo mi)
{
String signatureString = String.Join(",", mi.GetParameters().Select(p => p.ParameterType.Name).ToArray());
String returnTypeName = mi.ReturnType.Name;

if (mi.IsGenericMethod)
{
String typeParamsString = String.Join(",", mi.GetGenericArguments().Select(g => g.AssemblyQualifiedName).ToArray());

// returns a string like this: "Assembly.YourSolution.YourProject.YourClass:YourMethod(Param1TypeName,...,ParamNTypeName):ReturnTypeName
return String.Format("{0}:{1}<{2}>({3}):{4}", mi.DeclaringType.AssemblyQualifiedName, mi.Name, typeParamsString, signatureString, returnTypeName);
}

return String.Format("{0}:{1}({2}):{3}", mi.DeclaringType.AssemblyQualifiedName, mi.Name, signatureString, returnTypeName);
}
}

You can then simplify the comparison like this:

foreach (MethodInfo mi in yourType.GetMethods())
{
if (mi.CreateUniqueName() == stringStoredInDb) { /* do something */ }
}

How to print object ID?

The closest you can easily get (which won't be affected by the GC moving objects around etc) is probably RuntimeHelpers.GetHashCode(Object). This gives the hash code which would be returned by calling Object.GetHashCode() non-virtually on the object. This is still not a unique identifier though. It's probably good enough for diagnostic purposes, but you shouldn't rely on it for production comparisons.

EDIT: If this is just for diagnostics, you could add a sort of "canonicalizing ID generator" which was just a List<object>... when you ask for an object's "ID" you'd check whether it already existed in the list (by comparing references) and then add it to the end if it didn't. The ID would be the index into the list. Of course, doing this without introducing a memory leak would involve weak references etc, but as a simple hack this might work for you.



Related Topics



Leave a reply



Submit