.Net Unique Object Identifier

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

How do I obtain an ID that allows me to tell difference instances of a class apart?

Use ObjectIDGenerator class:

http://msdn.microsoft.com/en-us/library/system.runtime.serialization.objectidgenerator.aspx

Quote:

The IDs are unique for the life of the ObjectIDGenerator instance.

Using a hash table, the ObjectIDGenerator retains which ID is assigned
to which object. The object references, which uniquely identify each
object, are addresses in the runtime garbage-collected heap. Object
reference values can change during serialization, but the table is
updated automatically so the information is correct.

Object IDs are 64-bit numbers. Allocation starts from one, so zero is
never a valid object ID. A formatter can choose a zero value to
represent an object reference whose value is null.

Update

This is the code that solves the problem. In the aspect class, use the following:

public static ObjectIDGenerator ObjectIDGen = new ObjectIDGenerator();

then:

bool firstTime;
long classInstanceID = ObjectIDGenerator.GetId(args.Instance, out firstTime);

Update

Thought I'd post the code that this entire post is based on. This code helps to detect thread safety hotspots across an entire project, by triggering warnings if multiple threads access the same instance of a class.

Useful if you have 30k lines of existing code, and you want to add a more formal verification of thread safety (something which is extremely difficult to do normally). It does impact runtime performance, so you can remove it after running it for a few days in debug mode.

To use, add PostSharp + this class to your project, then add an aspect "[MyThreadSafety]" to any class. PostSharp will insert the code in "OnEntry" before every method call. The aspect propagates to all sub-classes and sub-methods, so you can add thread safety checks to an entire project with just one line of code.

For another example of this technique in action, see an example designed to easily add caching to method calls.

    using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Text;
using System.Threading;
using MyLogType;
using PostSharp.Aspects;
using System.Collections.Concurrent;
using PostSharp.Extensibility;

namespace Demo
{
/// <summary>
/// Example code based on the page from a Google search of:
/// postsharp "Example: Tracing Method Execution"
/// </summary>
[Serializable]
public sealed class MyThreadSafetyCheck : OnMethodBoundaryAspect
{
/// <summary>
/// We need to be able to track if a different ThreadID is seen when executing a method within the *same* instance of a class. Its
/// ok if we see different ThreadID values when accessing different instances of a class. In fact, creating one copy of a class per
/// thread is a reliable method to fix threading issues in the first place.
///
/// Key: unique ID for every instance of every class.
/// Value: LastThreadID, tracks the ID of the last thread which accessed the current instance of this class.
/// </summary>
public static ConcurrentDictionary<long, int> DetectThreadingIssues = new ConcurrentDictionary<long, int>();

/// <summary>
/// Allows us to generate a unique ID for each instance of every class that we see.
/// </summary>
public static ObjectIDGenerator ObjectIDGenerator = new ObjectIDGenerator();

/// <summary>
/// These fields are initialized at runtime. They do not need to be serialized.
/// </summary>
[NonSerialized]
private string MethodName;

[NonSerialized]
private long LastTotalMilliseconds;

/// <summary>
/// Stopwatch which we can use to avoid swamping the log with too many messages for threading violations.
/// </summary>
[NonSerialized]
private Stopwatch sw;

/// <summary>
/// Invoked only once at runtime from the static constructor of type declaring the target method.
/// </summary>
/// <param name="method"></param>
public override void RuntimeInitialize(MethodBase method)
{
if (method.DeclaringType != null)
{
this.MethodName = method.DeclaringType.FullName + "." + method.Name;
}

this.sw = new Stopwatch();
this.sw.Start();

this.LastTotalMilliseconds = -1000000;
}

/// <summary>
/// Invoked at runtime before that target method is invoked.
/// </summary>
/// <param name="args">Arguments to the function.</param>
public override void OnEntry(MethodExecutionArgs args)
{
if (args.Instance == null)
{
return;
}

if (this.MethodName.Contains(".ctor"))
{
// Ignore the thread that accesses the constructor.
// If we remove this check, then we get a false positive.
return;
}

bool firstTime;
long classInstanceID = ObjectIDGenerator.GetId(args.Instance, out firstTime);

if (firstTime)
{
// This the first time we have called this, there is no LastThreadID. Return.
if (DetectThreadingIssues.TryAdd(classInstanceID, Thread.CurrentThread.ManagedThreadId) == false)
{
Console.Write(string.Format("{0}Error E20120320-1349. Could not add an initial key to the \"DetectThreadingIssues\" dictionary.\n",
MyLog.NPrefix()));
}
return;
}

int lastThreadID = DetectThreadingIssues[classInstanceID];

// Check 1: Continue if this instance of the class was accessed by a different thread (which is definitely bad).
if (lastThreadID != Thread.CurrentThread.ManagedThreadId)
{
// Check 2: Are we printing more than one message per second?
if ((sw.ElapsedMilliseconds - this.LastTotalMilliseconds) > 1000)
{
Console.Write(string.Format("{0}Warning: ThreadID {1} then {2} accessed \"{3}\". To remove warning, manually check thread safety, then add \"[MyThreadSafetyCheck(AttributeExclude = true)]\".\n",
MyLog.NPrefix(), lastThreadID, Thread.CurrentThread.ManagedThreadId, this.MethodName));
this.LastTotalMilliseconds = sw.ElapsedMilliseconds;
}
}

// Update the value of "LastThreadID" for this particular instance of the class.
DetectThreadingIssues[classInstanceID] = Thread.CurrentThread.ManagedThreadId;
}
}
}

I can provide the full demo project on demand.

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.

how generate a unique id for 2 objects

Unique ID generation using GUID and Cryptography

Using GUID:

public string generateID()
{
return Guid.NewGuid().ToString("N");
}

"N" - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx (32 digits)

Or

using System.Security.Cryptography; // Import this Dll
public string Get8Digits()
{
var bytes = new byte[4];
var rng = RandomNumberGenerator.Create();
rng.GetBytes(bytes);
uint random = BitConverter.ToUInt32(bytes, 0) % 100000000;
return String.Format("{0:D8}", random);
}

Specify a unique identifier attribute for an object across webapi Models

I ended up writing my own Attribute and then looking up for it in the BaseController.

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public sealed class UniqueIdAttribute: Attribute
{
}

And in the BaseController Created method:

    protected CreatedNegotiatedContentResult<T> Created<T>(T content)
{
var props =typeof(T).GetProperties().Where(
prop => Attribute.IsDefined(prop, typeof(UniqueIdAttribute)));
if (props.Count() == 0)
{
//log this
return base.Created(Request.RequestUri.ToString(), content);
}
var id = props.FirstOrDefault().GetValue(content).ToString();
return base.Created(new Uri(Request.RequestUri + id), content);
}

Mark Gravell's post here helped me with getting the value of the property that has my custom attribute:
How to get a list of properties with a given attribute?

Along with a corresponding unit test for the controllers works fine for me.

Now I can just call Created(anyobject); from all ApiControllers without bothering about the different names people put for their IDs as long as they decorate it with my custom attribute.

Is there a Session-unique identifier that can be used as a cache key name?

The answer Yiyi You linked to explains it -- the Session.Id won't be static until you first put something into the Session collection. Like so:

HttpContext.Session.Set("Foo", new byte[] { 1, 2, 3, 4, 5 });

_keyName = HttpContext.Session.Id + "_searchResults";

ASP.NET Core: Session Id Always Changes

.NET Short Unique Identifier

This one a good one - http://www.singular.co.nz/blog/archive/2007/12/20/shortguid-a-shorter-and-url-friendly-guid-in-c-sharp.aspx

and also here
YouTube-like GUID

You could use Base64:

string base64Guid = Convert.ToBase64String(Guid.NewGuid().ToByteArray());

That generates a string like E1HKfn68Pkms5zsZsvKONw==. Since a GUID is
always 128 bits, you can omit the == that you know will always be
present at the end and that will give you a 22 character string. This
isn't as short as YouTube though.



Related Topics



Leave a reply



Submit