5

I am using Dictionary using objects like DirectoryInfo and FileInfo as keys. Is it safe to use them that way? How can I make sure an object type can be safely used this way?

leppie
  • 115,091
  • 17
  • 196
  • 297
d0001
  • 2,162
  • 3
  • 20
  • 46
  • Hi Daniel, personally i don't understand why you're using directoryinfo or fileinfo as keys.Personally i use to set a key and set the dictionary as dictionary(of string,Object).May show us a little bit of code in order to better understand why are you doing it? – makemoney2010 Jul 09 '14 at 18:27
  • Related: http://stackoverflow.com/questions/634826/using-an-object-as-a-generic-dictionary-key-in-net – tnw Jul 09 '14 at 18:27
  • Define "safely" in this context. What are your expectations? – Lasse V. Karlsen Jul 09 '14 at 18:30
  • http://stackoverflow.com/questions/18653083/what-can-you-use-as-keys-in-a-c-sharp-dictionary Sorry, but I am constantly amazed at how many questions are asked here when a search through MSDN, etc will give the answer. I guess if it were me I would actually just write the code and find out how it works - that's called programming. Not trying to bash anyone but I see a similar question asked everywhere in stackoverflow and have to wonder why there is so much duplication – Tab Jul 09 '14 at 18:33
  • Programming is also about writing stable code. If you rely on undocumented, but observed, behavior, there's no telling how long your code will seem to work. One of the "rules" when writing a `GetHashCode` implementation is that every time you call that method *on the same object instance* you should get the same value. In this respect, using a specific `DirectoryInfo` object as key is safe. If you expect two objects constructed around the same path string to be interchangeable as keys, the documentation states that no, you can't rely on that, and observed behavior supports that. – Lasse V. Karlsen Jul 09 '14 at 18:39
  • I have a program working and using DirectoryInfo. Hash doesnt always return same value but dictionary is matching so I asked because I was wondering if I had missed somethig. – d0001 Jul 09 '14 at 18:59

3 Answers3

8

In general, the only way to know exactly how this will behave is to check the reference source. You can check the documentation to see whether IEquatable<T> is implemented (in which case you'll get "expected" behavior), as well.

If the type in question doesn't override Equals and GetHashCode, then the default hashing and equality for any object will be used. This means you can use it as a key, but only if your lookups are being done with the same instance of the type, since the equality is reference equality by default for System.Object.

In this case, DirectoryInfo and related classes do not override those methods, which means you'll get the default equality and hashing of object, which is likely not what you want. I would, instead, recommend using the FullName property as a key, since it's a a string and provides the proper equality semantics for use in a dictionary.

Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • The *correct* way is to check the documentation. Unless behavior is documented, you should not rely on it. – Lasse V. Karlsen Jul 09 '14 at 18:31
  • 1
    @LasseV.Karlsen Unfortunately, the documentation (from what I've seen) doesn't consistently specify whether things override `Equals` and `GetHashCode`. You *can* check to see if it implements `IEquatable`, but this is one place where the docs in the framework seem to be lacking. – Reed Copsey Jul 09 '14 at 18:31
  • The documentation for DirectoryInfo specifically says GetHashCode is inherited from `Object`, and the documentation for `Object.GetHashCode` specifically says it does not guarantee uniqueness or consistency. – Lasse V. Karlsen Jul 09 '14 at 18:32
  • 1
    There always the reference sources to confirm! http://referencesource.microsoft.com/#mscorlib/system/io/directoryinfo.cs – dee-see Jul 09 '14 at 18:33
  • @LasseV.Karlsen Yes, but I've seen cases where `GetHashCode` is implemented for a type but that's not reflected in the documentation. – Reed Copsey Jul 09 '14 at 18:34
  • the user still has not defined the expectations. How is it possible to add advice on usage without knowing the requirements? – Tab Jul 09 '14 at 18:37
  • That may be true, but if the documentation doesn't mention it, you should not rely on it, even if you can inspect the disassembled code and see that the method is there and "doing the right thing" currently. There is no guarantee it will be there, or in that shape or form, in a future patch/hotfix/version of .NET. – Lasse V. Karlsen Jul 09 '14 at 18:37
  • 1
    @Tab It isn't possible. – Lasse V. Karlsen Jul 09 '14 at 18:38
  • @Tab It isn't possible, but it is possible to guess on the expectations. That's specifically why I said you could do it, and explained the behavior you'd get if you do - but also suggested that it's likely not what they want... – Reed Copsey Jul 09 '14 at 18:39
  • @Reed - understood - each to their own I guess – Tab Jul 09 '14 at 18:44
4

To use it as a key it would make sense that two DirectoryInfo objects that represent the same directory have the same hash code.

Let's see if it's the case!

new System.IO.DirectoryInfo(@"C:\").GetHashCode(); // 25422474
new System.IO.DirectoryInfo(@"C:\").GetHashCode(); // 48007696

The hash codes are different. You can use it as a key, but it won't make much sense. You'd be better off using the full path.

You can also see from the available sources that GetHashCode is not overridden.

dee-see
  • 23,668
  • 5
  • 58
  • 91
1

Normally, the objects would be recycled when the method is exited, but since you've added them to a container, they are 'pinned' in memory. So in that sense they're safe. However, if an external agent deletes the file or folder, then you have an object that refers to a non-existent entity. So test if they exist before attempting to interact with them.

SingleStepper
  • 348
  • 1
  • 10