none
Weird behavior with interface implementation RRS feed

  • Question

  • okay,

     

    so I have this base collection class which inherits from System.Collections.ObjectModel.Collection(of T) which as we know implements: IList(of T), ICollectio(of T), IEnumerable(of t), Ilist, icollection, ienumerable.  This is all great and exactly what I wanted out of this class.

    So i have taken my base collection class (a generic class) and derived from it a Keyed Collection, which implements IDictionary, and basically alows me to have an Indexed and Keyed class, which based on my original class allows for customized item sorting, while still retaining the dictionary's key based look ups.  A Very helpful and powerful class model. 

    So, given a situation where i wasn't thinking, knowing that my colleciton is MyKeyedCollection(of TKey, TItem) i figured I wanted a list of the keys to iterate through.  Granted I could expose my internal field beyond the protected property scope, but instead, that's why I implemented the IDictionary to do it.  But that would mean I would have to type cast each "key" in the keys collection of IDictionary.  so instead, i decided to typecast my collection as IDictionary(of TKey, TItem),(though i used the actual "types" in my typecast, it would just take too much effort to do it here).  THis came up with an error upon runtime and rightly so because I hadn't implemented IDictionary(of TKey, TItem). 

    So I decided to add it. 

     

    public class MyCollection(Of T)
       inherits System.Collections.ObjectModel.Collection(of T)
       implements ICloneable, IDisposable
    
    end class
    
    Public Class MyKeyedCollection(of TKey, TItem)
        inherits MyCollection(of TItem)
        implements IDictionary, IDictionary(of TKey, TItem)
    
    
    
    
    
        private _keys as MyCollection(of TKey)
        private _dict as Dictionary(of TKey, TItem)
    end class
    

    Pretty straight forward I would think.  I hit enter at the end of the line which populated all the necessary methods/properties of the new interface, and I went about filling them in, pretty much referencing the internal _dict field for a few that needed that darned KeyValuePair structure, and for the others, I simply used my already existing methods/properties of the MyKeyedCollection class.

    All went well, when I noticed this:

     

    Public Class EntityPropertyInfoList
        inherits MyKeyedCollection(of String, EntityStateType)
    
    end class
    
    ...
    
    Public Class MyBusinessObject
       private _entityStates as EntityPropertyInfoList
    
      public readonly property Modified as boolean
        get
          return _entityStates.Any
    
    (function(e) e <> EntityStateType.Unchanged)
        end get
      end property
    end class

    Error: "Any is not a member of _entityStates"

    Say WHAT!

    I delete the implementation of IDictionary(of TKey, TItem) from MyKeyedCollection and everything is back to normal working as it should. 

    My Question:

    A)  Why and How does the IDictionary(of TKey, TItem) implemenation override/supercede the Ienumabler and other implementation from the parent class?

    B) How can I make this implementation possible without destroying the existing functionality of the class structures, so that all my previous usage of linq, and ienumerable extensions will operate exactly as they had before but also providing me the ability to treat any templated KeyedCollection as a templated IDictionary?

     

    Thanks

    Jaeden "Sifo Dyas" al'Raec Ruiner



    "Never Trust a computer. Your brain is smarter than any micro-chip."
    PS - Don't mark answers on other people's questions. There are such things as Vacations and Holidays which may reduce timely activity, and until the person asking the question can test your answer, it is not correct just because you think it is. Marking it correct for them often stops other people from even reading the question and possibly providing the real "correct" answer.
    Saturday, April 10, 2010 1:33 AM

All replies

  • I am not very familiar with VB.NET since I use C#, so please excuse me. But since the concepts are the same with only syntax as the difference I think I can help.

    When you implement IDictionary(Of TKey, TItem) is inherits from IEnumerable(Of KeyValuePair(Of TKey, TItem)). So now your class implements two IEnumerable interface and the compiler doesn't know which one to use. So you can try casting to IEnumerable (Of EntityStateType)

    CType(_entityStates, IEnumerable(Of EntityStateType)).Any
    Saturday, April 10, 2010 3:12 AM
  • Can i do a reimplementation, or dual implementation so that it can handle both, the IEnumerable<TItem> and IEnumerble<Keyvaluepair> ?

    the reason is I have THOUSANDS of lines that utilize the original implementation of IEnumerable<T> from MyCollection<T>, which is subsequently is inherited by MyKeyedCollection<TKey,TItem>.  TO do the cast as you suggest would be to have to re-write countless operations already in place.  I just wanted to "add" the IDiectionary<TKey,TItem> implementation to the existing MyKeyedCollection.

    Thanks

    J"SD"a'RR


    "Never Trust a computer. Your brain is smarter than any micro-chip."
    PS - Don't mark answers on other people's questions. There are such things as Vacations and Holidays which may reduce timely activity, and until the person asking the question can test your answer, it is not correct just because you think it is. Marking it correct for them often stops other people from even reading the question and possibly providing the real "correct" answer.
    Saturday, April 10, 2010 6:29 PM
  • In C# you can use explicit interface implementation to implement IEnumerable<*> separately (in VB it is likely Implements statement or maybe other syntax).

    Another option is to return IDictionary<.,.> from a property and keep its implementation in separate private object (possibly calling into your main object).

    -Karel

    • Marked as answer by SamAgain Friday, April 16, 2010 10:25 AM
    • Unmarked as answer by JaedenRuiner Wednesday, April 21, 2010 7:02 AM
    Monday, April 12, 2010 9:04 PM
    Moderator
  • Hi JaedenRuiner,

    From these code:

    Public Class EntityPropertyInfoList
        inherits MyKeyedCollection(of String, EntityStateType)
    
    end class
    

     

    private _entityStates as EntityPropertyInfoList

     

    and these:

     

    Public Class EntityPropertyInfoList
        inherits MyKeyedCollection(of String, EntityStateType)
    
    end class
    

     

    We can know the relationship in your class inheritation.

    From these codes:

     

    Public Class MyKeyedCollection(of TKey, TItem)
        inherits MyCollection(of TItem)
    implements IDictionary, IDictionary(of TKey, TItem)

     

    We know your MyKeyedCollection class have how many kinds of interface to implement and inherit.

    After I look up the IDictionary in MSDN, I find that only generic IDictionary(Of TKey , TValue ) has "any" method.

    From the defination and usage example of this method as below:

    <ExtensionAttribute> _
    Public Shared Function Any(Of TSource) ( _
    	source As IEnumerable(Of TSource) _
    ) As Boolean
    
    Dim source As IEnumerable(Of TSource)
    Dim returnValue As Boolean
    returnValue = source.Any()
    
    Based on I understanding, I think you should implement IEnumerator to your MyKeyedCollection class, so that your class can support IEumerable interface.

    Hope this helpful to you!

    Have a nice day!


    Hope this helpful to you! If you have any further quetions, please feel free to let me know.
    Please mark the right answer at right time.
    Bset Regards,
    Tracy
    • Marked as answer by SamAgain Friday, April 16, 2010 10:25 AM
    • Unmarked as answer by JaedenRuiner Wednesday, April 21, 2010 7:02 AM
    Tuesday, April 13, 2010 10:19 AM
  • Ah, well, been busy for a while, and apparently SamAgain didn't read my signature post script, because with these responses, none were the answer, and only one person actually understood my problem, that being Sherif Elmetainy .  The problem is not what is implemented or how. But how .Net framework handles implementation inheritance.

    MyCollection(of T) implements IEnumerable, IEnumerable(of T). 

    I do not care for the default Generic Dictionary object (or interface for that matter) because it defines the Collection as a Collection of KeyValue Structures.  My Collection is of TItem.  the TKey is only there as a lookup reference for the TItem, and regardless of the argument, nothing will ever convince of a better theory.  Dictionary or collection does not matter, the collection is ALWAYS of the Item, not some indirect structure retaining both key and item.  No my  MyKeyedCollection overrides and bypasses this annoying behavior of the Dictionary<> class and IDictionary<> interface, by basically, separating the Dictionary lookup as an internal reference, while inheriting from the MyCollection, maintaining the Collection of TItem.  This allows for sortable, indexed lists, while providing the avialability for each item to be referenced by some key object, of whatever type.  So yea, i cannot do: MyKeyedCollection(of Integer, Object) because the Key Indexer and Index Indexer conflict on identical types.  But for that circumstance i would not be using a Keyed Collection.

    The Explicit Implemetation Does not Work in this circumstance, whether in C# or VB, because as Sherif pointed out, IDictionary<> implements IEnumerable<KeyValue<K,T>> .  This implementation overrides the IEnumerable<T> that is implemented by MyCollection.  I don't want it to. 

    I want to implement the facets of IDictionary<> through explicit implementation, which passes all interpretations of the interface implementation into private fields and properties to reference my internal class's design.  Thus IDict_Clear() does nothing except call my class's default public Clear() method. 

    The best example is using Delphi, because delphi has an Implements keyword:

    public class TMyItem : IDictionary<Key, Item>
      private
       FDict: Dictionary(Key, Item)
      protected 
       property Dict : Dictionary(Key, Item) IMPLEMENTS IDictionary<Key, Item>
    end class

    The above is VERY pseudo-code, and not syntactically accurate, but the usage of the Implements keyword is appaprent.  This allows me to not have to "re-implement" code that is implemented by one of my sub objects. Thus, when I typecast TMyItem to the IDictionary<> interface, all IDictionary<> methods and properties are actually routed to the internal FDict object field, while still providing IDictionar<> implementation to the TMyItem class, even though TMyItem doesn't explicitly implement anything of IDictionary<>.

    My implementation of MyKeyedCollection, acts similarly, but without the joy of that simple keyword indirection of implementation.  I have a field _dict as Dictionary(TKey, TItem).  the Implementation, explicitly declared, for IDictionary<TKey, TItem> is found in private Methods. IDict_<Name>. 

    The difference between the IDictionary and IDictionary<> interfaces, is that IDictionary too implements IEnumerable but since it isn't specified with that annoying KeyValue Structure, it doesn't override the inherited MyCollection: IEnumerable, or IEnumerable<TItem> implementation. 

    Thus:

    Public Class MyCollection(of TItem)
     Inherits Collection(of TItem)
    
    End Class
    
    Public Class MyKeyedCollection(of TKey, TItem)
      inherits MyCollection(of TItem)
      implements IDictionary
     
      private _dict as Dictionary(of TKey, TItem)
    
    	Private Overloads Sub IDict_Add(ByVal key As Object, ByVal value As Object) Implements System.Collections.IDictionary.Add
    		If (TypeOf key Is TKey) AndAlso (TypeOf value Is TItem) Then
    			Me.Add(CType(key, TKey), CType(value, TItem))
    		End If
    	End Sub
    
    	Private Sub IDict_Clear() Implements System.Collections.IDictionary.Clear
    		Me.Clear()
    	End Sub
      
    	Private Function IDict_Contains(ByVal key As Object) As Boolean Implements System.Collections.IDictionary.Contains
    		Return If(TypeOf key Is TKey, Me.HasKey(CType(key, TKey)), False)
    
    	Private Function IDict_GetEnumerator() As System.Collections.IDictionaryEnumerator Implements System.Collections.IDictionary.GetEnumerator
    		Return _dict.GetEnumerator
    	End Function
    '<etc: other IDictionary methods/properties defined similarly>
    end class
    
    
    
    dim obj as New MyKeyedCollection(of String, MyEType)
    
    obj.All(function(e) e.SomeBoolProperty)
    obj.Select(function(e) e.SomeValueProperty).ToArray()
    obj("MyKey1")

    All of the above works, and any method, function, whatever that requires an IEnumerable, an IEnumerable<T>, or IDictionary support this class just perfectly.

    What I was attempting was to simply add the IDictionary<> generic interface to the MyKeyedColleciton to provide Generic Typed Dicionary interface support.  BUt what it does is that the IDictionary<> generaic support overrides the Ienumerable and IEnumerable<T> provided by MyCollection, thus preventing the use of the Enumerable Extensions provided by Linq. 

    I want to support IDictionary<> but keeping the IEnumerable<KeyValueStruct> implementation...hidden, or implemented through private methods.  So that when I do

    obj.All() i'm refering to MyCollection.IEnumerable (or IEnumerable<>) implementation and when I do:

    DirectCast(obj, IDictionary<string, MyEType>) only THEN does the IEnumerable extension obj.All refer to the IEnumerable<KeyValueStruct>

    I do not believe it is possible, due to the way the .Net Framework inheritance and implementation is designed.  But It never hurts to ask.

    Thanks

    Jaeden "Sifo Dyas" al'Raec Ruiner

     

     

     


    "Never Trust a computer. Your brain is smarter than any micro-chip."
    PS - Don't mark answers on other people's questions. There are such things as Vacations and Holidays which may reduce timely activity, and until the person asking the question can test your answer, it is not correct just because you think it is. Marking it correct for them often stops other people from even reading the question and possibly providing the real "correct" answer.
    Wednesday, April 21, 2010 7:32 AM