Click here to Skip to main content
15,885,537 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi everyone.

I have a requirement to check the key of a hashtable and compare it's value. I thought the following code would have worked:

C#
private void Startup()
       {
           GetSettings(); // Get the test program settings from the text file.
           if (hsh_Settings.ContainsKey("TestMode") == true)
           {
               if (hsh_Settings["TestMode"] == "Production")
               {
                    SetProductionMode();
               }
               if (hsh_Settings["TestMode"] == "Engineer")
               {
                    SetEngineeringMode();
               }
           }
           else
           {
               SetProductionMode();
           }
       }


Unfortunately I received the following warning: Possible unintended reference comparison; to get a value comparison, cast the left hand side to type 'string'

To make this warning go away, I did as asked:

C#
private void Startup()
       {
           GetSettings(); // Get the test program settings from the text file.
           if (hsh_Settings.ContainsKey("TestMode") == true)
           {
               if ((string)hsh_Settings["TestMode"] == "Production")
               {
                    SetProductionMode();
               }
               if ((string)hsh_Settings["TestMode"] == "Engineer")
               {
                    SetEngineeringMode();
               }
           }
           else
           {
               SetProductionMode();
           }
       }



Now there are no warnings and the code works. My problem is that I don't properly understand the reason for the cast requirement. Perhaps there is a cleaner way of comparing hashtable values that does not require messy casting to be done?

Thanks in advance,

Brian
Posted
Updated 25-Sep-13 4:21am
v2
Comments
Richard C Bishop 25-Sep-13 10:24am    
The cast is required because you cannot compare two different datatypes. Another option would be to add .ToString() to the end of your hsh_Settings[""], but the cast is fine.
bh_ 25-Sep-13 10:33am    
Hello richcb, thanks for the reply.

So the story behind this hashtable is that I have a text file with some settings in it, like this:

<pre lang="vb">
AutoHighLimit = 2E
ModIndex = 2B
AutoLowLimit = 2B
AutoUpdateRange = 10
ModIndexMode = Manual
TestMode = Engineering</pre>

And then I have a function called GetSettings() which iterates through the lines of the text file, first populating the keys with the text value on the far left, and then making the value of that key equal to the text on the other side of the '=' sign, not including the whitespace. So, as an example, after running GetSettings() there will be a key called AutoHighLimit and its value will be "2E".

And that's where the source of my confusion begins. My understanding was that the hashtable already contained string values. Why, then, do I have to cast to a string in the example I gave above? Clearly my understanding is not correct! :)

Thanks,

Brian

Yes, there is much cleaner approach. Actually, your solution is pretty dirty from the very beginning: you are using a non-generic hash table which inherently based on type casting. In other words, compile-time element type is System.Object, so you need to do type casts if you store objects of other types (which are still objects but have different run-time types).

All such collections (except specialized ones) have been rendered obsolete as early as of .NET v.2.0, when generics were introduced. The were not formally marked with System.ObsoleteAttribute just because there is nothing wrong with using it in legacy software units, for compatibility, but using them in newly developed software makes no sense, ever.

In your case, you should use the type System.Collections.Generic.Dictionary<string, string>:
http://msdn.microsoft.com/en-us/library/xfhwa508.aspx[^].

See also: http://msdn.microsoft.com/en-us/library/System.Collections.Generic.aspx[^].

Non-generic non-specialized collections have gone, don't use them anymore.

[EDIT]

As I see you are still confused with the cast. You need to understand how strings are compared and how default comparison between reference-type objects is done. Normally, references are compared. But you can redefine comparison method System.Object.Equals(System.Object), to compare object in some different way, let's say, semantically. If this is done, you have a choice between "==" comparison (which can be redefined separately) and comparison which always checks referential identity, using System.Object.ReferenceEquals. Please see:
http://msdn.microsoft.com/en-us/library/system.object.aspx[^].

Compiler does not "know" that one operand is a string and compares references, which is not what you meant to do. For strings, it compares string contents. System.String is a reference class which closely mimic value semantic. It is much more complex then most people think. For understanding, please see:
http://msdn.microsoft.com/en-us/library/system.string.intern.aspx[^],
http://msdn.microsoft.com/en-us/library/system.string.isinterned.aspx[^],
http://en.wikipedia.org/wiki/String_intern_pool[^].

You really need to understand reference and value types and working with references. These concepts are fundamental to .NET and CLI.

—SA
 
Share this answer
 
v3
Comments
bh_ 25-Sep-13 10:51am    
Okay, this sounds like it could be the solution for me. In light of your explanation I accept your "dirty code" criticism. The only thing I would say in defense is that use of "legacy software units" clearly doesn't make sense, as you said, but the problem is having the knowledge that it is a legacy software unit in the first place, which I certainly did not have. I have a background in perl which is where my habit of hashtables comes from.

Thanks for the reply I will be looking into your suggestion this afternoon and I'll give it a try!

Thanks again,

Brian
Sergey Alexandrovich Kryukov 25-Sep-13 10:59am    
You don't need any "defense"; with your background it was a natural move, so you only miss some part of FCL, so what? But thank you for understanding.

And I added a big section on comparison. It's not that trivial, but hope I explained it in detail. This is really something what you need to understand. I appreciate your desire to get to the essence of things. You really need to understand such things, regardless your application goals. So, your follow-up questions, if any, will be welcome.

Are you accepting the answer formally now (green "Accept" button)?

—SA
Maciej Los 25-Sep-13 11:10am    
Agree, 5ed!
Sergey Alexandrovich Kryukov 25-Sep-13 11:16am    
Thank you, Maciej.
—SA
bh_ 1-Oct-13 5:55am    
Thanks Sergey.

All: I found the following reference to give a good overview/use of the various collection types available in C# http://www.dotnetperls.com/collections
 
Share this answer
 
Comments
bh_ 25-Sep-13 10:38am    
Thanks Jameel. My confusion is still present because I expected the type of the hashtable value to already be a string, hence no need for a cast.
Jameel VM 25-Sep-13 10:56am    
then i recommend is to use Dictionary<tkey, tvalue="">.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900