views:

144

answers:

2

AssemblyInstaller.Install expects a System.Collections.IDictionary.

Am I right to be 'allergic' to using non-generic collections such as Hashtable or should I get over myself?!

e.g.

using System.Collections.Generic;
using System.Configuration.Install;
using System.Reflection;
using AssemblyWithInstaller;

namespace InstallerDemo
{
    class InstallerDemo
    {
        static void Main(string[] args)
        {
            var savedState = new Dictionary<object, object>();
            // i.e. as opposed to something that implements IDictionary:
            //var savedState = new System.Collections.Hashtable()
            var assembly = Assembly.GetAssembly(typeof (MyInstaller));
            var ai = new AssemblyInstaller(assembly, new[] {"/LogFile=install.log"});
            ai.Install(savedState);
            ai.Commit(savedState);
        }
    }
}

Additionally the compiler has no issue with this decalration:

var savedState = new Dictionary<string, object>();

But will anything bad happen at runtime if someone uses something other than strings as keys?


Update [Reflector to the rescue]

var savedState = new Dictionary<string, object>();

Confirming what Jon says, Dictionary implements IDictionary as follows:

void IDictionary.Add(object key, object value)
{
    Dictionary<TKey, TValue>.VerifyKey(key);
    Dictionary<TKey, TValue>.VerifyValueType(value);
    this.Add((TKey) key, (TValue) value);
}

...so in verifying the key it will throw an exception when the type of the key doesn't match that used when declaring the particular specialization of the generic Dictionary (and likewise for the type of the value):

private static void VerifyKey(object key)
{
    if (key == null)
    {
        ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
    }
    if (!(key is TKey))
    {
        ThrowHelper.ThrowWrongKeyTypeArgumentException(key, typeof(TKey));
    }
}
+4  A: 

Since the Installer is accepting an IDictionary-Object, it should be able to deal with any Dictionary passed to him. At least that's my opinion...if I take an Interface, I need to be able the handle any implementation of it.

Also, I'd suggest that you just try it.

Bobby
We can't expect legacy code to know about generics. It's going to call Add(object, object) and my implementation is expecting a string key so 'm trying to think if there are case where things will go bad at runtime.
rohancragg
Anyway, thanks Bobby. I'll try this and update the question with my results.
rohancragg
I tried it and it works....
rohancragg
+2  A: 

This works because Dictionary<TKey, TValue> implements IDictionary - but it will indeed fail at execution time if someone calls IDictionary.Add(object, object) with a non-string key - you'll get an ArgumentException.

Note that the IDictionary<TKey, TValue> interface itself doesn't extend IDictionary - it's just that the Dictionary<TKey, TValue> implementation also implements IDictionary.

Jon Skeet
OK, good to know, thanks. But what's your opinion on whether it's better for me to prefer Dictionary<string, object> over HashTable?At least this way I communicate better what I (now know) is the requirement of this particular usage of the IDictionary (i.e. that it should actually use a string key and an object value).
rohancragg
It depends how and when you prefer to detect errors. If you're happy for it to go "bang" immediately when someone tries to add a non-string key, then I think it's a good plan.
Jon Skeet
So I guess we should only consider doing this if we wrote the installer ourselves or we otherwise know that it's OK to assume that a string key will be used...
rohancragg