Creating a Hash Code for a Data Type

Problem
You have created a class or structure that will be used as a key in a Hashtable or Dictionary<T,U>. You need to overload the GetHashCode method in order to return a good distribution of hash values (the Discussion section defines a good distribution of hash values). You also need to choose the best hash-code algorithm to use in the GetHashCode method of your object.

        public static void CreateHashCodeDataType()
        {
            SimpleClass simpleClass = new SimpleClass("foo");

            Hashtable hashTable = new Hashtable();
            hashTable.Add(simpleClass, 100);

            Dictionary<SimpleClass, int> dict = new Dictionary<SimpleClass, int>();
            dict.Add(simpleClass, 100);
        }

        public class SimpleClass
        {
            private string text = "";

            public SimpleClass(string inputText)
            {
                text = inputText;
            }

            public override int GetHashCode()
            {
                return (ShiftAndAddHash(text));
            }

            public int ShiftAndAddHash(string strValue)
            {
                int hashCode = 0;

                foreach (char c in strValue)
                {
                    hashCode = (hashCode << 5) + (int)c + (hashCode >> 2);
                }

                return (hashCode);
            }
        }

        public int SimpleHash(params int[] values)
        {
            int hashCode = 0;
            if (values != null)
            {
                foreach (int val in values)
                {
                    hashCode ^= val;
                }
            }

            return (hashCode);
        }

        public int FoldingHash(params long[] values)
        {
            int hashCode = 0;
            if (values != null)
            {
                int tempLowerVal = 0;
                int tempUpperVal = 0;
                foreach (long val in values)
                {
                    tempLowerVal = (int)(val & 0x000000007FFFFFFF);
                    tempUpperVal = (int)((val >> 32) & 0xFFFFFFFF);
                    hashCode^= tempLowerVal ^ tempUpperVal;
                }
            }

            return (hashCode);
        }

        public int ContainedObjHash(params object[] values)
        {
            int hashCode = 0;
            if (values != null)
            {
                foreach (int val in values)
                {
                    hashCode ^= val.GetHashCode();
                }
            }

            return (hashCode);
        }

        public int CryptoHash(string strValue)
        {
            int hashCode = 0;
            if (strValue != null)
            {
                byte[] encodedUnHashedString = 
                    Encoding.Unicode.GetBytes(strValue);

                byte[] key = new byte[16];
                RandomNumberGenerator.Create().GetBytes(key);

                MACTripleDES hashingObj = new MACTripleDES(key);
                byte[] code = 
                    hashingObj.ComputeHash(encodedUnHashedString);

                // use the BitConverter class to take the 
                // first 4 bytes and use them as an int for
                // the hash code
                hashCode = BitConverter.ToInt32(code,0);    
            }

            return (hashCode);
        }

        public int CryptoHash(long intValue)
        {
            int hashCode = 0;
            byte[] encodedUnHashedString = 
                Encoding.Unicode.GetBytes(intValue.ToString());

            SHA256Managed hashingObj = new SHA256Managed();
            byte[] code = hashingObj.ComputeHash(encodedUnHashedString);

            // use the BitConverter class to take the 
            // first 4 bytes and use them as an int for
            // the hash code
            hashCode = BitConverter.ToInt32(code,0);    

            return (hashCode);
        }

        public int ShiftAndAddHash (string strValue)
        {
            int hashCode = 0;
            
            foreach (char c in strValue)
            {
                hashCode = (hashCode << 5) + (int)c + (hashCode >> 2);
            }
            
            return (hashCode);
        }

        public int CalcHash(short someShort, int someInt, long someLong,
            float someFloat, object someObject)
        {
            int hashCode = 7;
            hashCode = hashCode * 31 + (int)someShort;
            hashCode = hashCode * 31 + someInt;
            hashCode = hashCode * 31 + 
                (int)(someLong ^ (someLong >> 32));
            long someFloatToLong = (long)someFloat;
            hashCode = hashCode * 31 + 
                (int)(someFloatToLong ^ (someFloatToLong >> 32));

            if (someObject != null)
            {
                hashCode = hashCode * 31 + 
                    someObject.GetHashCode();
            }

            return (hashCode);
        }

        public int ConcatStringGetHashCode(int[] someIntArray)
        {
            int hashCode = 0;
            StringBuilder hashString = new StringBuilder();

            if (someIntArray != null)
            {
                foreach (int i in someIntArray)
                {
                    hashString.Append(i.ToString() + "^");
                }
            }
            hashCode = hashString.GetHashCode();

            return (hashCode);
        }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Simulation of Browser Caching during load tests

In a VS load test that contains Web tests, the load test attempts to simulate the caching behavior of the browser. Here are some notes on how that is done:

  • There is a property named on each request in a Web test named “Cache Control” in the Web test editor (and named “Cache” on the WebTestRequest object in the API used by coded Web tests).
  • When the Cache Control property on a request in the Web test is false, the request is always issued.
  • When the Cache Control property is true, the VS load test runtime code attempts to emulate the Internet Explorer caching behavior (with the “Automatically” setting).This includes reading and following the HTTP cache control directives.
  • The Cache Control property is automatically set to true for all dependent requests (typically for images, style sheets, etc embedded on the page).
  • In a load test, the browser caching behavior is simulated separately for each user running in the load test.
  • When a virtual user in a load test completes a Web test and a new Web test session is started to keep the user load at the same level, sometimes the load test starts simulates a “new user” with a clean cache, and sometimes the load test simulates a return user that has items cached from a previous session. This is determined by the “Percentage of New Users” property on the Scenario in the load test. The default for “Percentage of New Users” is 0.

Important Note: When running a Web test by itself (outside of the load test), the Cache Control property is automatically set to false for all dependent requests so they are always fetched; this is so that they can be displayed in the browser pane of the Web test results viewer without broken images.