5

I want to implement EqualityComparer<T> for feature classes so that I can stuff them into a Dictionary or HashSet.

For motivation, say that I am looping over many IFeature objects which belong to different feature classes, and I want to set field values for each. FindField is inefficient to perform inside of a loop. If I have a Dictionary<IFeatureClass, Dictionary<string, int>> to give me the index of a given field, this operation would be much faster.

So, how does one uniquely identify a feature class object? The AliasName property is not unique. The IName object should be, but I'm not sure how to compare them, or how to hash them. Is IDataset.Name unique to each feature class? If it is, it must include the full data path, right?

2 Answers 2

6

Well, all things being equal, I would normally point out that your .NET dictionary is implemented as a tree, and if it were balanced, (otherwise the time complexity would be worse) the time complexity would be O(log n) while ESRI's FindField is internally implemented as a Hash table, and thus a time complexity of O(1) which is much better.

Of course I said all things being equal. And in this case, they are not, because you are using .NET an there is the issue of context switching and marshalling which is better explained as the first item of a previous related post that I did about ArcObjects performance.

My recommendation to you is to switch to .NET Hash tables instead of the Dictionaries.

OK, moving on.

To answer your second question, under non-managed conditions(i.e not Java or .NET) the answer is super simple, just compare pointers of objects! The unique-instancing model (per thread) of the factory pattern used by the GeoDatabase guarantees that the objects will be the same.

For .NET, its multi-generation memory model throws this technique out of the window - from the .NET side.

Nevertheless, for comparing pointer equality of most ArcObjects, you can use IClone's IsIdentical method which basically compares memory addresses in COM land.

So what is the solution for the FeatureClass case (that AFAIK, doesn't implement IClone). You have to take the long route :(

Use IDataset::name on the FC to get a fully qualified name, and then go to the parent Workspace and verify its connection properties to make sure the db is the same. Funny enough, this also covers an interesting Versioning case (Two FCs that are connected to the same DB, but are connected to different versions of the same FC).

Update: My original observation about .NET Dictionaries is incorrect. Apparently, they are implemented as hash tables as Scott points out :)

4
  • Actually, the .NET Dictionary class is implemented as a Hash Table, and thus looking up an item by key is O(1). See the Remarks section here. Because Esri cautions against using it within loops, I've alwyas assumed that FindField is O(n). How did you learn that it was O(1)? Is Esri just worried about the overhead of a hash table lookup? So IClone.IsIdentical() tests for reference equality? Does it give different results than Object.ReferenceEquals()? If the .NET call is unreliable for COM objects, I have some refactoring to do.
    – Scott B
    Commented Oct 19, 2011 at 20:19
  • @ScottB Oh, it goes to show my ignorance of certain .NET data structures. Going to edit my answer :) Commented Oct 19, 2011 at 22:04
  • 1
    FindField is O(1) + COM overhead. How do I know? I worked at the GeoDatabase team for several years maintaining and extending this code. ESRI is worried that you are paying unnecessary COM marshaling price. AFAIK Object.ReferenceEquals is testing for equality of reference of the .NET wrapper, which is very different than the address of the COM object itself (which is tested by IsIdentical). Unless the ESRI shipped wrappers have been modified to use IClone::IsIdentical (they could, I do not know though), they would have different behavior. Commented Oct 19, 2011 at 22:14
  • 1
    Thanks Ragi! This answer, and your insightful performance post here, are the most helpful ArcObjects information I've read this year. And now I further regret turning down my offer from Esri for a spot on the GeoDatabases team; I might have been as well informed as you :)
    – Scott B
    Commented Oct 19, 2011 at 22:21
1

If you want to work with datasets you can implement IEnumDatasetName to walk through all of your feature classes. IDataset.Name will be unique, but you will have to get the full path - if all of your data is stored in the same place this is simple, if not, you'll have to do a bit of work to grab the full paths first.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.