Sign in to follow this  
Spa8nky

[C#] Generating a unique ID for each object instance

Recommended Posts

If I wanted a quick and simple way of generating a unique string ID for each instance of a class would the following method suffice:

this.iD = this.GetType().Name.ToString() + this.GetHashCode().ToString();

Or do the resident coding gurus have a better suggestion for assigning a unique string based ID? Thanks guys.

Share this post


Link to post
Share on other sites
Normally I just make a static int member called ID. I initialize it as 1 with a static constructor.

I then have a static method called getID that returns an int.


public static int getID()
{
return ID++;
}



Now you can get a unique ID any time you want.

theTroll

Share this post


Link to post
Share on other sites
These GUID (as strings) are used for indentifying Quads in a resource pool of Quads.

E.G.


//=============================================
//--------- [Add Quad to Resource Pools] ------
//=============================================
// If the Dictionary associated with the current effect doesn't contain the string key (quad_ID)
if (!this.vertices_Pool[this.effect_Type].ContainsKey(quad_GUID))
{
// Add the string key (quad_ID) to the Dictionary and
// Create a new array of Vertices (maximum of 4) for the current key
this.vertices_Pool[this.effect_Type].Add(quad_GUID, new VertexPositionNormalExtra[GameConstants.QUAD_NUMBER_OF_VERTICES]);

// Add the current Quad's vertices to the Dictionary under the quad_ID key
this.vertices_Pool[this.effect_Type][quad_GUID] = quad_Current.Vertices;
}
else
{
// Add the current Quad's vertices to the Dictionary under the quad_ID key
this.vertices_Pool[this.effect_Type][quad_GUID] = quad_Current.Vertices;
}

Share this post


Link to post
Share on other sites
I think GUIDs are a bit overkill in this situation. Generating GUIDs is somewhat slowish if I recall correct, esp. when you're going to create thousands of them in a situation where an ID would suffice.

However, why exactly are you storing your quads with an ID? Wouldn't it be more efficient to just check if an object instance is already in the list? And on dictionaries, why not just calculate the hash code? The hash isn't used to store the object by, just as a way to quickly index it.

Toolmaker

Share this post


Link to post
Share on other sites
Yes I believe you are right. GUIDs might be a bit of overkill in this situation.

I guess using the static getID method would be the fastest.

However, as 10000s Quads are created, updated and deleted from various points in the Dictionary in no particular order, I must know which ones to update, delete etc.

The ID will not change for the Dictionary but when using an index of an array of Quads the index would change when Quads are deleted, this is why I use a Dictionary with IDs.

I can also easily get the number of Vertices and Indices to draw as follows with a Dictionary:


public void Draw(Camera camera)
{
foreach (string key in vertices_Pool.Keys)
{
// Check to see if there are any Quads to draw with the current key (effect)
if (vertices_Pool[key].Count != 0)
{
// Reset index and current vertex and index count to 0 for current key (effect)
index = 0;
vertex_Count = 0;
index_Count = 0;

// Check each GUID (Global Unique ID) key to see if VertexPositionNormalExtra array contains any data
foreach (string iD in vertices_Pool[key].Keys)
{
// If the VertexPositionNormalExtra array is not null
if (vertices_Pool[key][iD] != null)
{
// Copy the vertex data to the drawable vertices for this effect
vertices_Pool[key][iD].CopyTo(vertices_Drawable, vertex_Count);

// As all Quad indices are identical, don't work out indices until drawable Quads are being calculated
this.indices_Drawable[index++] = (short)(0 + vertex_Count);
this.indices_Drawable[index++] = (short)(1 + vertex_Count);
this.indices_Drawable[index++] = (short)(2 + vertex_Count);

this.indices_Drawable[index++] = (short)(1 + vertex_Count);
this.indices_Drawable[index++] = (short)(3 + vertex_Count);
this.indices_Drawable[index++] = (short)(2 + vertex_Count);

// Increase the vertex count by the number of vertices in a Quad
vertex_Count += GameConstants.QUAD_NUMBER_OF_VERTICES;

// Do the same for indices
index_Count += GameConstants.QUAD_NUMBER_OF_INDICES;
}
}

// Make sure there are Quad vertices to draw (will be 0 if all vertex arrays associated with iD are null)
if (vertex_Count != 0)
{
// If reusing Quads (E.G. BulletManager) vertex_Count should not keep increasing if maximum avaialable Quad value (MAX_BULLETS) has been reached
//Console.WriteLine(vertex_Count);
DrawQuadrangles(key, camera);
}
}
}
}




EDIT:

Something like this will do the trick?


// Globally Unique IDentifier
public static class GUID
{
private static int ID;
public static int GetUID()
{
ID++;
return ID;
}
}

Share this post


Link to post
Share on other sites
I wouldn't make a whole new class. I would add the static member and static method to the class the needs the UID. This keeps it where it is going to be used.

theTroll

Share this post


Link to post
Share on other sites
Quote:
Original post by Toolmaker
However, why exactly are you storing your quads with an ID? Wouldn't it be more efficient to just check if an object instance is already in the list? And on dictionaries, why not just calculate the hash code? The hash isn't used to store the object by, just as a way to quickly index it.

Toolmaker


QFE. A HashSet might even be appropriate here, though I'm naively skeptical of the need for a pool in the first place.

Share this post


Link to post
Share on other sites
(If ID counting is still needed after previous comments)

Personally, I would keep it simple and minimalistic, and implement a small ID-counter that is atomically incremented (read: it shall be thread safe) upon each generateId() call.


So, if you need a global id-counter for each class:

static class ID<T> {
static long id = 0;
static public long generateNewId () {
return System.Threading.Interlocked.Increment (ref id);
}
}


Or if you want to have local id-counters:
class ID {
long id = 0;
public long generateNewId () {
return System.Threading.Interlocked.Increment (ref id);
}
}



And if you want to load the counter from some file, then call some function that loads a saved id from some file, instead of intializing it to zero.

Share this post


Link to post
Share on other sites
Thanks very much for all your help with this one guys.

Using a GUID has also solved the query I had in my previous thread.

Share this post


Link to post
Share on other sites
Quote:
Original post by Spa8nky
Thanks very much for all your help with this one guys.

Using a GUID has also solved the query I had in my previous thread.


How do you use the GUIDs? I think if you use them in some acceleration structure (e.g. a complete node in a Kd-tree is only 8 bytes in ray tracing *) or for groups of vertices, they waste way too much memory; I think 16 bytes per single ID, when your ID is only used within your application, is total exaggeration.

Or is it somehow mandatory to identify your data in a solar system wide pool? I seriously mean it; do you know that when you lay down each possible 64bit value in a row, with a sub-millimeter distance (afair 0.002 cm), you'll already range the whole solar system? With 65 bit you double that range, 66 bits is 4x the range, et cetera.

Can you guarantee that the number of unique id's never exceeds 18,446,744,073,709,551,616 (==18,446,744,073,709 million == 18,446 million billion)? Use a uint64 (half of a GUID). Never exceeds 4,294,967,296? Use a uint32 (1/4 of a GUID). Never exceeds 65,536? You are lucky, you can use a uint16 (1/8 of a GUID).

Not specifically addressed at you, just throwing that in: Having way more powerful machines these days, nobody has to wonder about why applications still seem to crawl like back in the day, when so many application developers are wasting so much bandwidth, computing time, and memory.

*: I once crunched a special Kd-tree node into 4 bytes (afair) to store 130 million triangles in a real time ray tracer, in less then 512 MiB of main memory. Using another size optimisation, 2 byte nodes would have been possible.

Share this post


Link to post
Share on other sites
Quote:

How do you use the GUIDs?


They are used to represent objects in pools that are drawn as Quads.

E.G.

Bullets. I can have a maximum of say 500 bullets. Therefore there will only be a maximum of 500 GUIDs for all bullets.

All bullets are created during load time and then cycled through. If there are 501 bullets then the bullet that was first created will be replaced with the 501st bullet, still leaving 500 bullets with the maximum of 500 GUIDs.

Heck, I could even get away with returning a ushort for my GUID. Am I wasting bandwidth, computing time, and memory using this method?

I was just very glad it worked, but now you got me worried :(

Share this post


Link to post
Share on other sites
If the upper limit of your buffer is known, why even use a dictionary and GUIDs? You could just as well use a fixed sized array and use the array index as ID. Instead of removing quads from that array you could just set them to null. That would not only save the need for a GUID but speed up lookups as well.

Share this post


Link to post
Share on other sites
Quote:

If the upper limit of your buffer is known, why even use a dictionary and GUIDs?


The dictionary is there to order each Quad under the effect type (HLSL shader) for which is to be drawn.

GUIDs are needed because for the time being it seems more logical referencing Bullet Quads that way (E.G. Easier to debug).

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this