Declaring a Class, sort of

CryoEnix

Regular
Joined
Jan 11, 2003
Messages
93
Location
Wrexham, Wales
Hey guys, long time no see!

I've recently been away from VB.NET, playing with Blitz3D. It's an SDK designed to make simple directX powered games using the BASIC syntax, and since coming back to VB I've been thinking about how I can implement what I've learned from it in my applications.

You see, ordinarily in VB when I need lots of the same class, I'll create an array of them - resizing the array when necessary. But in Blitz I can create classes like so:

m.clsTimer=New clsTimer

the 'm' designation can then be used with the scope of declaration to refer to the said class, and if I need to access it from outside the declaration I can loop through all instances of clsTimer with:

for m.clsTimer=each clsTImer

next

...and delete an instance (from within said loop) with:

delete m

this technique allows me to create and destroy classes at will, without needing to keep track of them within a public-scope array. I know you're just begging me to ask my question, so here it is:

How do I implement this class technique within VB8.NET? Is it even possible? Even a link to a page that explains it would be greatly appreciated. Thanks!
 
If I'm understanding you correctly (which based on my last few posts seems unlikely :S) then it's probably a case of Blitz3D managing the objects for you. Basically every object you create will be added to an array/collection in the background. Then the delete keyword is used to access this array, search for the object passed as the parameter and remove it. Essentially what is happening is the same as you were doing before, but it's managed for you.

To the best of my knowledge you can't create your own keyword and as such you couldn't make an exact copy of the code. You could probably use Shared methods to create similar functionality at a specific level, but I'm not sure how you'd go about writting a generic version.
 
Hey Cags - yeah mate, you understood me perfectly. I've just been surfing the net, and I've found a solution to my problem - Cags nailed it - I needed to create my own collection for the classes. Cheers!
 
Don't know what it is that you found on the net, but for caching objects I've found that a static generic class that maintains a simple list or dictionary of objects is very convinient. The best part is that because static generic classes create a set of all the static variables for each generic parameter, you automatically get a separate cache for each type of object, and with a very small amount of code.
 
This is the solution I found on the net - sorry, I was eating before so didn't have the time to show my findings. Hope this helps others who shared my problem/apiffany!

1; Declare the collection
Although Blitz3d does this automatically, you need to declare a virtual 'bucket' for all of the classes to be thrown into:

Code:
Public collect As New Collection()

2; Creating a class within the collection
Running on the same principle as creating a new instance of your class normally, you need to inform the system that the class is being made specifically for the 'collect' bucket:

Code:
collect.Add(New clsTimer(),ClassID)

The ClassID is a string, used as a primary key to locate that particular instance specifically instead of looping though all of the collection. It is optional, so no need to worry about it -but I found it necessary to delete the Class afterwards.

3; Looping through the collection

Code:
For Each d As clsTimer In collect
   msgbox (d.StringPropertyOfSomeSort)
next

Simple as. each iteration through the loop will give 'd' the properties of another Class within the collection (I know, I know - more of a memory address than copying of properties, but I'm going layman here)

4; Deleting an item in the collection

Code:
 collect.Remove(ClassID)

That optional String used as a key? You can use it to easily destroy one of the classes.


I think that shows everything I needed, and although it looks a bit more daunting than using a dynamic Class Array, it's far easier in my opinion.

On that note, do any of you guys have alternatives to these when it comes to accessing large groups of data? I figured since this post has been answered, we might as well play with some thread deviation!
 
Well, here is a spiffed up version of the generic cache I was talking about:
C#:
static class Cache<T>
{
    // Backing collection
    static Dictionary<string, T> values;
    
    static Cache() {
        // Create a dicationary with case-insensitive strings for keys.
        values = new Dictionary<string, T>(StringComparer.InvariantCultureIgnoreCase);
    }

    public static T GetItem(string key){
        return values[key];
    }

#region Add/Remove methods
    /// <summary>
    /// Adds an object with a specified key to the cache.
    /// </summary>
    /// <param name="key">The key under which the object is stored.</param>
    /// <param name="value">The object to store.</param>
    public static void Add(string key, T value){
        values.Add(key, value);
    }
    /// <summary>
    /// Adds an object to the cache, generating a key automatically.
    /// </summary>
    /// <param name="value">The value to store.</param>
    public static void Add(T value){
        values.Add(
            //Create a key based on the object's hash code, ideally
            //ensuring that unique objects obtain unique keys.
            value.GetHashCode().ToString(),
            value);
    }

    /// <summary>
    /// Removes an object from the cache by specifying the key.
    /// </summary>
    /// <param name="key">The key of the object to remove from the cache.</param>
    /// <returns>A value indicating success or failure of the operation.</returns>
    public static bool Remove(string key) {
        return values.Remove(key);
    }
    /// <summary>
    /// Removes an object from the cache by specifying the key.
    /// </summary>
    /// <param name="value">The object to remove from the cache.</param>
    /// <returns>A value indicating success or failure of the operation.</returns>
    public static bool Remove(T value) {
        string key = null;
        foreach(KeyValuePair<string, T> item in values){
            if(item.Value.Equals(value)) {
                key = item.Key;
                break;
            }
        }

        if(key == null) return false;

        return values.Remove(key);
    }

    /// <summary>
    /// Removes any items from the cache where the item meets the condition specified.
    /// </summary>
    /// <param name="condition">A delegate which processes an item and returns a boolean value
    /// indicative of whether or not the value meets a condition.</param>
    public static void Remove(Predicate<T> condition) {
        string[] keys = new string[values.Count];
        values.Keys.CopyTo(keys, 0);

        foreach(string key in keys) {
            if(condition(values[key])) values.Remove(key);
        }
    }
    /// <summary>
    /// Removes any items from the cache where the key meets the condition specified.
    /// </summary>
    /// <param name="condition">A delegate which processes a key and returns a boolean value
    /// indicative of whether or not the value meets a condition.</param>
    public static void Remove(Predicate<string> condition) {
        string[] keys = new string[values.Count];
        values.Keys.CopyTo(keys, 0);

        foreach(string key in keys) {
            if(condition(key)) values.Remove(key);
        }
    }

    /// <summary>
    /// Removes all items from the cache.
    /// </summary>
    public static void Clear() {
        values.Clear();
    }
#endregion

#region Enumerators
    /// <summary>
    /// Gets an enumerable collection of all the objects stored in the cache.
    /// </summary>
    public static IEnumerable<T> Values {
        get {
            return values.Values;
        }
    }
    /// <summary>
    /// Gets an enumerable collection of all the keys that identify objects in the cache.
    /// </summary>
    public static IEnumerable<string> Keys {
        get {
            return values.Keys;
        }
    }
#endregion

}

Very simple to use. You automatically get a separate cache for each class type, and the use of keys is strictly optional. Duplicate keys are not allowed.
C#:
public void Demonstrate() {
    Cache<int>.Add("five", 5);
    Cache<int>.Add("six", 6);

    // Shows "5" (the key "FIVE" is the same as "five" because the cache uses case-insensitive keys)
    MessageBox.Show(Cache<int>.GetItem("FIVE").ToString());

    // Throws exception, there is no object stored under the key "six"
    // in the Cache<double> collection.
    MessageBox.Show(Cache<double>.GetItem("six").ToString());

    // Shows "5", then "6"
    foreach(int value in Cache<int>.Values) {
        MessageBox.Show(value.ToString());
    }
}

Of course, all the Cache<T> class really does is wrap and globalize the Dictionary class, but it makes project-wide caching much, much easier. Insert the code into your project, and then you don't need to declare any collections or maintain references to them.

Of course, a more elaborate global collection class could be written to create the namespace-like scheme that Blitz3D appearently uses, but I personally don't have much use for such a class.
 
I must admit the method suggested by marble_eater is more akin to what I was thinking than using a simple collection, but I'm glad you got it working for you. Any particular reason you choose C# to post in marble_eater? It's not the simplest bit of code to convert over to VB.
 
Hmm... didn't put much though into the language, although I suppose I certainly should have. The rest of the thread is in VB. The reason I used C# is because I do most of my programming in C# and I already had that class written in C# (I just fancied it up for posting). If anyone wants it in VB, I'll gladly translate it.
 
Back
Top