.net.devcity.weekly ---
If you are unable to see the message, visit http://www.devcity.net/newsletter/archive/devcity/devcity20050515.htm

Advertisement

AdvertisementAdvertisement

The newsletter is compiled by DevCity.NET NewsMasters Ged Mead and Mike McIntyre

Advertisement

Table Of Content:

Advertisement

Fadzai Chamba

Random segments of code

There have always been ghosts in the machine. Random segments of code that gather together to form unexpected behavior. No, sorry, I've been watching iRobot too many times lately. Let me do this again. There has always been a need to generate random numbers in code. Many practical examples of this need exist, ranging from computer games and dynamic application behavior to nefarious gambling and cheating schemes. In the past, this was done using functions, but .NET has introduced a Random class.

After the introduction

The Random class is not difficult to use. In fact it is so simple that you are likely to make mistakes. The following is a true story that occurred recently when I was helping out a friend (Bevin) with some code he was working on. He did not disclose his reasons for delving into random numbers and gave me a test project in C# he was learning in.

The test project was simple; at the click of a button, enable a timer with an interval of 1000 milliseconds. At each Tick event, generate 2 random numbers and change the size of the form according to the values obtained from the generation. Simple? Not really, not if you think you know what you are doing like I did. Here is the code that he had.

//generate the random numbers...
System.Random w = new System.Random(100);
System.Random h = new System.Random(100);
this.Size = new Size(Convert.ToInt32(w), Convert.ToInt32(h));

This code compiled, and since I had not used random numbers in .NET yet, it looked OK but he kept getting an invalid cast exception. This of course was not his first attempt, the code had ended up like this after many attempts, and since he is still learning both programming and .NET he was out of ideas.

Enter Fabulous

You know the saying; an expert is called in to share the blame. I happened to visit him in his office and he showed me what was happening. He sent it to my laptop from his via infra-red and I tried it and got the same exception he was getting. This is when he told me he had been trying for so long.

I opened what I feel should be a developer's best friend, the Object Browser, and checked out the properties and methods for the Random class. I saw the Next method and immediately thought that must be the answer. He modified the code and ended up with this:

private void tmr_Tick(object sender, System.EventArgs e)
{
    System.Random r = new System.Random(100);
    int w = r.Next();
    int h = r.Next();
    this.Size = new Size(w, h);
}

He looked at me with a smirk on his face when the form changed size only once. I played around with the Next method's overloads but didn't get much joy there either. The code was now looking like this:

System.Random r = new System.Random(100);
int w = r.Next(500);
int h = r.Next(500);
this.Size = new Size(w, h);

I set a value for the maximum number to generate but again the form would resize only once. He thought it was an issue with the timer at one point and had changed to the System.Timers.Timer so I checked whether or not he had changed the AutoReset value. This allows you to have a timer that fires only once. All was well so the problem was somewhere else. I changed the timer to a System.Threading.Timer to see if this would improve but still there was no joy and he seemed to be enjoying my ordeal. He had found something that was beyond me, or so he thought.

Random Generation

I then began to explain to him the concept of Random number generation. When generating a random number, or series thereof, one would need a value called a seed. This is used to calculate the first random number that would be generated. Subsequent numbers are calculated from the last one generated. I told him that in BASIC (most dialects of BASIC that I had used) we would initialize the random number generator with a value called Timer. This value is calculated using the system timer; I would suppose the number of ticks since midnight, or since the machine was turned on. It is unlikely that you would get the same value when you run the code at different times or on different machines.

He is kind of anti-BASIC so he thought this was me giving up but what I was looking for was a way to get the Random class to be initialized with a value similar to the Timer value in BASIC. I was not in much luck and then I remembered something else. If you initialize a random number generator with a value, it will always give you the same numbers in the same order every time. This made me realize that the random segment of code (the part generating the Random object) was being run every second, initializing a new generator with the same value. The immediate solution was to take out the declaration and have code such as:

System.Random r = new System.Random(100);

private void tmr_Tick(object sender, System.EventArgs e)
{
    int w = r.Next(500);
    int h = r.Next(500);
    this.Size = new Size(w, h);
}

Now there was a bit of joy, and triumph on my face. Once again, my friend Bevin had failed to find something I was incapable of solving, sort of. He ran it again and then we came back to the same issue I had explained before. While it was changing sizes every second now, it was coming up to the same sizes in the same order meaning that whatever the real application was for, it would be predictable, which was most likely not a good thing.

I now had to find a way to use a Timer generated value to initialize the random number generator. And another problem occurred, zero was an invalid value in his real problem and at one point, the form was as high as the title bar, which was bad. I recalled from the overloads of Next, that there was one that took two integers for minimum and maximum value. So I edited the code to something like this:

int h = r.Next(500, 50);

This compiled but when I ran the code I was told that "minValue cannot be greater than maxValue." I knew that, really I did. When you type this code, the first (and probably the default) overload you get has maxValue only, so naturally, you would try to put the maxValue then the minValue. The other overload starts with minValue however, and this is something that I found rather annoying since I had bigger problems. Just thought I would mention that in case anyone else comes up against this.

Back to the Browser

I called on my best friend again; the Object Browser and he told me that there are two constructors for this class. At this point I had not yet typed out the code to create the generator so I had not seen this. The other constructor takes no arguments; it was really nice to deal with someone who didn't argue. The note on the constructor was this "Initializes a new instance of the Random class, using a time-dependent default seed value."

This was just what I needed and I didn't have to do anything to get it. I don't know why he used 100 as a seed actually, but thought that he might have his reasons. The code then changed to this:

System.Random r = new System.Random();
private void tmr_Tick(object sender, System.EventArgs e)
{
    int w = r.Next(50, 500);
    int h = r.Next(50, 500);
    this.Size = new Size(w, h);
}

When we ran this a few times, we agreed that this was producing truly random numbers, the values being returned were now non-deterministic and I emerged victorious, which was nice.

Make it peri-peri chicken

Well with this, I think Bevin owes me a pizza, don't you think? Well I do, and I would like it to be Peri-peri chicken flavor. This experience showed me however that no matter how comfortable one may be with a product, technology etc. there is some simple concept about it that will seem rather tricky. It is very easy to overlook the fundamentals of a technology and underestimate certain areas. This makes for the most annoying code problems because you know that it is totally possible but it isn't done the way you expect. The moral of the story is, if you value your pizza, stock up on knowledge of what might otherwise be thought as pretty useless trivia so that you can get your friends to buy you some.

Have a great day and happy coding.

by Mike McIntyre

This article discusses the Object class' overloadable Equals and Overrideable GetHashCode methods. The default implementations of these two methods in the Object class don't do anything very useful. It is left to you to overload the Equals method and override the GetHashCode to make them useful in classes you derive from the Object class. This article explains why and provides some 'how to' information with sample code.

Here are two code examples. Explanations follow the examples.

Example Code - Student Class

Public Class Student

    ' StudentID field.
    Private _StudentID As Integer
    ' StudentID property.
    Public Property StudentID() As Integer
        Get
            Return _StudentID
        End Get
        Set(ByVal Value As Integer)
            _StudentID = Value
        End Set
    End Property

    ' Name field.
    Private _Name As String
    ' Name property.
    Public Property Name() As String
        Get
            Return _Name
        End Get
        Set(ByVal Value As String)
            _Name = Value
        End Set
    End Property

    ' Overload the Object class' Equals method.
    Public Overloads Overrides Function Equals(ByVal obj As Object) _
      As Boolean
        ' The Student database table's primary key consists of one 
        ' column, the StudentID column. StudentID is immutable and 
        ' unique data.
        ' Use this object's StudentID data to test whether the object 
        ' passed into this method is equal to this student object.
        Try
            Return MyBase.Equals(obj) And _
              (CType(obj, Student).StudentID = Me.StudentID)
        Catch
            Return False
        End Try
    End Function

    ' Override the Object class' GetHashCode method.
    Public Overrides Function GetHashCode() As Integer
        '  Use the same object data we used when we overloaded the 
        '    Equals method.
        '  Since StudentID is immutable, unique, and an integer value
        '    we can return it 'as it' as the hash code for this Student
        '    object. (a hash code is an integer value).
        Return _StudentID
    End Function

End Class

Example Code - WarehouseBin Class

Public Class WarehouseBin

    ' WarehouseID field.
    Private _WarehouseID As String
    ' WarehouseID property.
    Public Property WarehouseID() As String
        Get
            Return _WarehouseID
        End Get
        Set(ByVal Value As String)
            _WarehouseID = Value
        End Set
    End Property

    ' BinID field.
    Private _BinID As Integer
    ' BinID property.
    Public Property BinID() As Integer
        Get
            Return _BinID
        End Get
        Set(ByVal Value As Integer)
            _BinID = Value
        End Set
    End Property

    ' Overload the Object class' Equals method.
    Public Overloads Overrides Function Equals(ByVal obj As Object) _
      As Boolean
        ' The database table WarehouseBin's primary key consists of
        '   two columns, the WarehouseID and the BinID columns.
        ' Combined together, WarehouseID and BinID is immutable and 
        '   unique data.
        ' Use the object's WarehouseID data and BinID data to test 
        '   whether the object passed into this method is equal to 
        '   this WarehouseBin object.
        Try
            Return MyBase.Equals(obj) And _
              CType(obj, WarehouseBin).WarehouseID = _
              Me.WarehouseID And (CType(obj, WarehouseBin).BinID = Me.BinID)
        Catch
            Return False
        End Try
    End Function

    ' Override the Object class' GetHashCode method.
    Public Overrides Function GetHashCode() As Integer
        '  Use the same object data we used when we overloaded the 
        '    Equals method to generate a unique hash code.
        '  Since WarehouseID is a string and BinID is a integer we
        '    convert the BinID to string, append it to WarehouseID,
        '    call GetHashCode on the result and return the result as
        '    this WarehouseBin object's hash code.
        Return CInt((Me._WarehouseID & Me._BinID.ToString).GetHashCode)
    End Function
End Class

Equals Method

The purpose of the Object class's Equals method is to test for equality between the value of an object and another object.

The Object class' Equals method's default implementation checks two variables to see if they both point to the same object in memory. In other words, the Equals method checks the location in memory each variable references and if it's the same memory location returns True.

Most of the time we want our classes to check for equality between two objects based on the data they contain, not their location in memory. For example, when comparing two BankAcount objects we probably want to determine they are equal if they have the same unique account number.

Overload the Equals method when you author a class so that immutable and unique data in an object instantiated from your class is used to check the equality of one instance of your class to another.

A good example of immutable and unique data is the database primary key associated with entities such as a students, warehouse bins, and employees.

A primary key may consist of one database column or more.

If the primary key for a database table named Student consists of one column, the StudentID column, then StudentID is the immutable and unique data to use in a Student class' Equals method.

See the Example Code - Student Class above.

GetHashCode Method

The purpose of the Object class' GetHashCode method is to get a hash code suitable for use in hashing algorithms and data structures like a hash table.

The Object class' GetHashCode method's default implementation returns a unique index for each instance, determined by the runtime - not by data in the object.

A class that overloads the Equals method should always override the GetHashCode method. Two objects that are equal should generate the same hash code. The easiest way to implement this is to use the same object data your use when you overloaded the Equals method to generate a unique hash code.

Override the GetHashCode method when you author a class by using the same data you used to overload your Equals method to generate an object's hash code.

If the primary key for a database table name WarehouseBin consists of two columns, the WarehouseID and BinID columns, then WarehouseID plus BinID is the immutable and unique data to use in a WarhouseBin class' Equals method.

See the Example Code - WarehouseBin Class above.

Advertisement
Articles: Recent Articles

WMI Connections Made Easy in VB.NET

Martin de Klerk (VBCity Leader emdek) has written this very useful guide to the tricky area of Windows Management Instrumentation (WMI). As he says in his introduction, "It is intended as a rough and practical (but by no means complete!) guide to get you up and running with WMI as a VB.NET programmer. Without running into brick walls, that is.

Read the explanation, analyze the code, or download the sample here

Text Techniques

Presenting text vertically in a label - or on most any other control, for that matter - is fairly easy .... However there are some tips and tricks worth knowing, especially if you need to break out of the default orientation which writes the text from top to bottom.

Everything you need to know about these techniques can be found in the article here

http://www.devcity.net/
Advertisement

We encourage you to pass this issue of
.net.devcity.weekly on to anyone you know with an interest in .NET technology and News You Can Compile

Manage Your Subscription Here.

You are currently subscribed as '*EMAIL*' to .net.devcity.weekly.

Click here to unsubscribe.

Thanks for reading!

Contact:
vbCity.com, LLC
4957 Lakemont Blvd SE C4 #331
Bellevue, WA 98006


DevCity.NET is hosted by FullControl.NET

Copyright vbCity.com, LLC 2003. All Rights Reserved.