locked
How to Implement Interface Indexed Property on existing Indexed property Class

    Question

  • Okay,

    This is the point where I have to comment to the creators of C# that the disallowing of INdexed properties seems to be a VERY foolish oversight. 
    Case and point: Interface implementation. 

    Given I have a class that is an indexed collection of items.

    thus I have already in the class:

    TItem this[int index] {get {..} set{..}}

    TItem this[TKey item] {get {..} set{..}}

    but I also what this class to implement IDictionary for portability and reusablility across the .Net framework.  This was quite simple to achieve in VB since

    Property IDict_Item(key as object) as Object implement IDictionary.Item

    But in C# how in the world will I achieve both aims?  granted I could create another overload of the this[] indexer, but in then I'll get those:
    Ambiguous reference to this[x].  and if TKey in the creation of the generic class happens to be of type object I'm really screwed. 

    Ideas? 
    Jaeden "Sifo Dyas" al'Raec Ruiner
    "Never Trust a computer. Your brain is smarter than any micro-chip."
    Monday, September 28, 2009 3:12 PM

Answers

  • So, if you're trying to implement IDictionary<TKey,TItem>, but also allow for an int indexer, you can do it by an explicit interface implementation, as so:

    class MyClass<TKey, TItem> : IDictionary<TKey, TItem>
    {
      // implement class:

        TItem this[int index] { get {..} set {...} }
        TItem IDictionary<TKey, TItem>.this[TKey key]
        {
            get { ... }
            set { ... }
        }
    }


    Reed Copsey, Jr. - http://reedcopsey.com
    • Marked as answer by JaedenRuiner Tuesday, September 29, 2009 1:57 PM
    Monday, September 28, 2009 4:10 PM
  • And if you don't want the generic IDictionary, Reed's answer is still valid, ie, implement it explicitly.
        class MyClass<TItem> : IDictionary
        {
            public TItem this[int index] { get {...} set {...} }
            public TItem this[TItem key] { get {...} set {...} }

            #region IDictionary Members

            object IDictionary.this[object key] { get {...} set {...} }

            // .. other IDictionary implementations

            #endregion
        }
    • Marked as answer by JaedenRuiner Tuesday, September 29, 2009 1:57 PM
    Monday, September 28, 2009 4:26 PM

All replies

  • So, if you're trying to implement IDictionary<TKey,TItem>, but also allow for an int indexer, you can do it by an explicit interface implementation, as so:

    class MyClass<TKey, TItem> : IDictionary<TKey, TItem>
    {
      // implement class:

        TItem this[int index] { get {..} set {...} }
        TItem IDictionary<TKey, TItem>.this[TKey key]
        {
            get { ... }
            set { ... }
        }
    }


    Reed Copsey, Jr. - http://reedcopsey.com
    • Marked as answer by JaedenRuiner Tuesday, September 29, 2009 1:57 PM
    Monday, September 28, 2009 4:10 PM
  • And if you don't want the generic IDictionary, Reed's answer is still valid, ie, implement it explicitly.
        class MyClass<TItem> : IDictionary
        {
            public TItem this[int index] { get {...} set {...} }
            public TItem this[TItem key] { get {...} set {...} }

            #region IDictionary Members

            object IDictionary.this[object key] { get {...} set {...} }

            // .. other IDictionary implementations

            #endregion
        }
    • Marked as answer by JaedenRuiner Tuesday, September 29, 2009 1:57 PM
    Monday, September 28, 2009 4:26 PM
  • No. 

    I'm not trying to implement IDictionary<TKey,TItem> because the default generic IDictionary implementation sucks.  It forces the usage of a KeyValuePair structure as the item object within the list.  I do not like this idea at all. 

    so, I have a class MyCollection<TItem> : Generics.Collection<TItem> {}

    the MyCollection class implements on the fly sorting, pre-post insertion/removal events, and other checkers.  I prefer default value based returns as opposed to exceptions.  exceptions are all well and good, but it is frankly damned annoying to have to perform a  try..catch everytime i access the index of a collection.  My methods simply allow me to go:  if Collection[X] != null { } as oppsed to try { collection[x].blah() } catch{whocares}.  the default generic collection does not afford this design so the MyCollection handles that for me.  SImilar with Dictionaries and Keys.  I do a check first if the Key exists in the dictionary and return the default value for the TItem if the key does not exist. 

    I then decided to create upon that the MyKeyedCollection() which has a key reference to a collection object via an private Dictionary member field.  Thus, I can have a decendent class that is based upon TKey/TItem and since i know what TKey and TItem are, I can set up the Dictionary Reference Keys on the fly at insertion, or I can handle it in external events for the OnInserting() event from the MyCollection object, (allowing me to cancel the insertion if necessary, as well as defining the Key for the MyKeyedCollection), or I can simply Add(Key,Value) at item insertion point.  Thus MyKeyedCollection directly implements ICollection, ILIst and a few others (like IDisposable, ICloneable) from the .Net Generic Collection<TItem> class.  This allows me to access the Collection[int] = TItem, and Collection[TKey] = TItem.  the default IDictionary the Dictionary[TKey] = KeyValuePair<TKey,TItem>  I do not like that behavior, i want the key to directly return the item associated with the key, not the structure that contains both the key and the item.  My method there is no need for the structure at all, and since the keys are also retained in an indexed based ICollection, I can directly correlate all Keys to Items, and thus have items which have no keys, for some collections only a few items need a "key" lookup, where as others I either don't need to process, or can be simply indexed by ordinal position.

    Being that the MyKeyedCollection class is indeed a "Dictionary" of sorts, I wanted to add the IDictionary support for other usages, which is fantastically easy to do in VB.Net.  The amusing thing is that I create the VB.Net Assembly, and then go to C# and reference the assembly the Class works just beautifully as I intended (baring the get_/set_ accessors of indexed properties not labeled Item, ie: Collection.Keys(i) becomes Collection.get_Key(i)) But to define the class in C# thus far is impossible. 

    This of course also extends into the "Programmer" limitation for declaring Class methods which implement interface members as private.  Many classes in the entirety of the Microsoft .Net framework implement ISupportInitialize members, but they are declared "Private" which means I have to Cast the object into an ISupportInitialize to access the method directly, and thus cannot "override" the methods as they should be allowed.  Even Re-implementation does not work, because one cannot execute the "base" method of the Interface as the interface has no "base" to reference.  Yet, when I try to declare a method as "Private" and have it implement an Interface's Member, I get an error.  If Microsoft can do it, why can't I !!!  These are the things that frustrate me, and so, as much as I can basically not care about the private method declaration I MUST be able to implement the IDictionary upon a class which already has two overloaded this[] indexed property accessors. 
    Thanks
    Jaeden "Sifo Dyas" al'Raec Ruiner


    "Never Trust a computer. Your brain is smarter than any micro-chip."
    Monday, September 28, 2009 4:37 PM
  • If you implement the interface explicitly you don't have to use the public access modifier. Be aware though that the interface methods are still publicly accessible when you class is cast to the interface type.
    Monday, September 28, 2009 5:10 PM
  • Granted.  BUt I've got this error on:

    private object this[object key] {
    }

    Error: this[object key] does not implement IDictionary.this[object key] as private this[object key] is not declared public.  So that sort of defeats that Idea.
    J"SD"a'RR

    for this i definitely prefer the Delphi key word IMplements.  it works something like this:

    TMyCollection = class(Collection, IDictionary)
       private _dict as Dictionary

       property InternalDict as Dictionary implements IDictionary;
    end;

    This design allows me to determine where the methods are and which interface methods they implement.  At least VB gives me somewhat of the same control by allowing me to name the "method" whatever I want and then define which interface member the declaration implements.  WHy does not C# maintain the same idea?  As it is, implementing interfaces in C# insanely clutters up class declarations.  for any collection based object that happens to implement IDictionary now must have 2 Adds, 2 Removes, 2 this[]s, 2 Clears.  that is overkill.  the idea of an interface is to implement functionality without the interface knowing how the implementation occurs.  it appears (i'm not saying it is, just the surface impression) that C# was not as well thought out with this concept as C++, Delphi, or VB.Net.

    J"SD"a'RR

    "Never Trust a computer. Your brain is smarter than any micro-chip."
    Monday, September 28, 2009 5:59 PM
  • Jaeden:

    What Delphi is doing is exactly the same as doing this in C#:

    object IDictionary.this[object key] { ... }


    This is private when you're using your class directly, but allows you to use is as an IDictionary by explicitly implementing it.  THe delphi "Implements" keyword is doing the same thing (in IL) as doing this in C#.


    Reed Copsey, Jr. - http://reedcopsey.com
    Monday, September 28, 2009 6:01 PM
  • Oh, no.  Delphi is using the internal object class field to implement the class's interface members. 

    The Equivalent in C# pseudo syntax is:

    public class MyDictionary : IDictionary {
       private _dict as Dictionary = new IDictionary();

       public Property InternalDict as Dictionary Implements IDictionary {
          get { return _dict;}
          set {_dict = value;}
       }
    }

    MyDictionary table = new MyDictionary();
    ((IDictionary)table).Add(Key,Value); -> this equates to:  table.InternalDict.Add();

    Delphi allows another level of indirection on interface implementation.

    But as I pointed out above. the use of object this[object key] required the use of the public keyword, and makes my life a bit more complicated given the universal "object" type which often interferes with ints, and TKeys, etc. 

    J"SD"a'RR
       

    "Never Trust a computer. Your brain is smarter than any micro-chip."
    Monday, September 28, 2009 6:44 PM
  • Seems like you make false assumptions here:
    I'm not trying to implement IDictionary<TKey,TItem> because the default generic IDictionary implementation sucks.  It forces the usage of a KeyValuePair structure as the item object within the list.  I do not like this idea at all. 

    (...)

    the default IDictionary the Dictionary[TKey] = KeyValuePair<TKey,TItem>Jaeden "Sifo Dyas" al'Raec Ruiner


    False.
    Dictionary[TKey] = TValue

    This of course also extends into the "Programmer" limitation for declaring Class methods which implement interface members as private.  Many classes in the entirety of the Microsoft .Net framework implement ISupportInitialize members, but they are declared "Private" which means I have to Cast the object into an ISupportInitialize to access the method directly, and thus cannot "override" the methods as they should be allowed.  Even Re-implementation does not work, because one cannot execute the "base" method of the Interface as the interface has no "base" to reference.  Yet, when I try to declare a method as "Private" and have it implement an Interface's Member, I get an error.  If Microsoft can do it, why can't I !!!  These are the things that frustrate me, and so, as much as I can basically not care about the private method declaration I MUST be able to implement the IDictionary upon a class which already has two overloaded this[] indexed property accessors


    In C#, you can implement ISupportInitialize that way, as has already been said.

    Like this:

    class BaseClass : ISupportInitialize
    {
        void ISupportInitialize.BeginInit() { ... }
        void ISupportInitialize.EndInit() { ... }
    }


    TMyCollection = class(Collection, IDictionary)
       private _dict as Dictionary

       property InternalDict as Dictionary implements IDictionary;
    end;


    Does this create a property that returns an IDictionary, or does this delegate the implementation to an internal object?

    Tuesday, September 29, 2009 12:35 PM
  • Seems like you make false assumptions here:
    I'm not trying to implement IDictionary<TKey,TItem> because the default generic IDictionary implementation sucks.  It forces the usage of a KeyValuePair structure as the item object within the list.  I do not like this idea at all. 
    False.
    Dictionary[TKey] = TValue
    So True. My bad on that one. I was typing faster than my brain. its the ICollection Implementation within the IDictionary<> implementation (as IDictionary implements certain ICollection members). All the ICollection members within the IDictionary implement KeyValuePair(Of TKey,TValue) which is annoying. I'd rather the KeyValuePair never be seen heard or used. Primarily because it is a Structure instead of a Class.
    This of course also extends into the "Programmer" limitation for declaring Class methods which implement interface members as private.  Many classes in the entirety of the Microsoft .Net framework implement ISupportInitialize members, but they are declared "Private" which means I have to Cast the object into an ISupportInitialize to access the method directly, and thus cannot "override" the methods as they should be allowed.  Even Re-implementation does not work, because one cannot execute the "base" method of the Interface as the interface has no "base" to reference. 


    In C#, you can implement ISupportInitialize that way, as has already been said.

    Like this:

    class BaseClass : ISupportInitialize
    {
        void ISupportInitialize.BeginInit() { ... }
        void ISupportInitialize.EndInit() { ... }
    }

    Ahh, no, i meant that say, look at the BIndingSource implementation of ISupportInitialize, and ISupportInitializeNotification. All the methods implements the interfaces are necessary to be run, but they cannot be overridden in any fashion. By re-implementing ISupportInitialize you damage the way the class is supposed to operate. This by itself basically limits the ability to descend from the BindingSource class (which I've done but it wasn't easy).

    But this point does lead into that I did eventually find the issue and resolve it, thanks to Reed above. I'm not too familiar with C# and since the code-completion didn't initially suggest it, I was unware I could prefix the "this[]" notation with the Interface. so i was constantly getting conflicts between TItem this[key], TItem this[int], object this[object], as well as I was getting this issue with the Idictionary version of the this[] needing to be declared public. When I tried the object IDictionary.this[object] {} I was able to leave it private and everything resolved itself. So thanks for that Reed .

    TMyCollection = class(Collection, IDictionary)
       private _dict as Dictionary

       property InternalDict as Dictionary implements IDictionary;
    end;

    Does this create a property that returns an IDictionary, or does this delegate the implementation to an internal object?


    Both. Usually these delegate implementations are left on a protected scope for only descendent classes to see. The property does actually return an IDictionary object, but with the implements keyword it delegates the implementation of the IDictionary interface to an internal object. This was most useful with IDispatch for COM. That interface is typically implemented the same, while providing greater functionality across COM lines than simply IUnknown, but there is also the 3 standard methods from inherited from IUnknown that need to be implemented. It was common practice to have: MyClass = Class(WhateverParent, IDispatch) private _iObj: TInterfacedObject; protected property UnkImpl: TInterfacedObject implements IUnknown,IDispatch; End; Of course my syntax is rusty, but the general idea was that one didn't have to write the _addRef,_Release, and QueryInterface methods as they were handled by the TInterfacedObject, so one only had to implement the specific members they wanted to handle. Though that's just a different language and there are quite a few other percs and flaws to every language, i'm just surprised that C# does't allow from interface member delegation. IE: like the VB style : Property X implements Interface.PropertyY. The two names do not have to be similar. C# seems to do it via the explecit implementation of Interface1.PropertyX, Interface2.PropertyX, PropertyX, so we have three methods all with the same name overloading each other (if they can) but two of them are prefixed by the interface. Interesting design, one which I will play with in the future. Thanks for the ideas and discussion, definitely some food for thought on C# implementations.

    Thanks
    Jaeden "Sifo Dyas" al'Raec Ruiner
    "Never Trust a computer. Your brain is smarter than any micro-chip."
    Tuesday, September 29, 2009 1:56 PM