tags:

views:

138

answers:

2

I'm new to the .Net world and I'm trying to figure out how inheritance and interfaces work exactly. I am trying to implement a Dictionary<string,string> that keeps all the keys as upper case strings. In F# my first naive stab was

type UpperDictionary1() = 
    inherit Dictionary<string, string>()
    override this.Add (key: string, value : string) =
        base.Add(key.ToUpper(), value)

That doesn't work because Dictionary Add is sealed. However dropping the override (and shadowing Add instead?) works:

type UpperDictionary2() = 
    inherit Dictionary<string, string>()
    member this.Add (key: string, value : string) = 
        base.Add(key.ToUpper(), value)

What is the quickest and most appropriate way to implement a special form of dictionary class?

Also, does this relate to Google's ForwardingSet in Java. Are forwarding sets simply an easier way to add this type of functionality or am I missing the point completely?

+3  A: 

I think what you want here is to implement the IDictionary interface. This will allow you to interact with your type as an IDictionary (Add, Remove, etc.) and you can just forward most of the calls to a private Dictionary member.

Check this out, too.

emptyset
It seems overkill to have to add all the methods, like Remove. But I guess that's considered good practice?
Tristan
True, but it's not so bad because you're just forwarding those methods to your private member. Also, you could reject a key with a custom exception if wasn't in uppercase.
emptyset
A: 

I really don't see implementing all of this interface as best practice and I highly doubt it's all correct even though it compiles. I'd suggest just making your own interface.

type UpperDictionary() = 
    let dictionary = new Dictionary<String, String>()

    interface IDictionary<string, string> with
        member this.Add(key: string, value : string) = dictionary.Add(key.ToUpper(), value)
        member this.Add(kvp) = dictionary.Add(kvp.Key.ToUpper(), kvp.Value)
        member this.ContainsKey(key) = dictionary.ContainsKey(key.ToUpper())
        member this.Contains(kvp) = dictionary.TryGetValue(kvp.Key.ToUpper(), ref kvp.Value)
        member this.Item with get key = dictionary.Item(key) and set key value = dictionary.Item(key) <- value
        member this.Count with get() = dictionary.Count
        member this.IsReadOnly with get() = false
        member this.Keys = dictionary.Keys :> ICollection<String>
        member this.Remove key = dictionary.Remove(key)
        member this.Remove(kvp : KeyValuePair<String,String>) = dictionary.Remove(kvp.Key.ToUpper())
        member this.TryGetValue(key, value) = dictionary.TryGetValue(key, ref value)
        member this.Values = dictionary.Values :> ICollection<String>
        member this.Clear() = dictionary.Clear()
        member this.CopyTo(array, arrayIndex) = (dictionary :> IDictionary<string, string>).CopyTo(array, arrayIndex)
        member this.GetEnumerator() = dictionary.GetEnumerator() :> IEnumerator
        member this.GetEnumerator() = dictionary.GetEnumerator() :> IEnumerator<KeyValuePair<String,String>>
gradbot
Though it is good .NET exercise.
gradbot
I guess I was wondering if this is really the recommended approach, given that my second method works and would just needs to add a second Add and CopyTo method. It seems overkill to have to implement all the methods, if you really just want an object backed by a real dictionary but with some extra functionality on top. That's what I was gathering from Google's ForwardingSets.
Tristan
It is the approach if you want to enforce the constraints you've specified. Like I said above, you can also enforce only accepting uppercase keys for `this.ContainsKey` or `this.Remove(key)`.
emptyset