开发者

Type Dictionary?

Has anybody heard of a "type dictionary" that uses types as keys and supports inheritance?

In my application I'd like to have a dictionary from types to functions, sort of like this:

Dictionary<Type, Func<object, object>> Transformers;

The idea is that it would be used to transform an object in some fashion based on its type:

// Transform an object 'obj'
object result = Transformers[obj.GetType()](obj)

An ordinary dictionary has the disadvantage that the type must match exactl开发者_StackOverflow中文版y. So if I've written a transformer for IList<T>, there's no use putting it in the Transformers dictionary because no object has the type IList<T> (only T[], List<T>, etc.) In other words, if obj is a List<T>, the transformer for IList<T> will not be found by a lookup in an ordinary dictionary.

Assuming there is no such thing as a TypeDictionary<TValue>, I might consider writing one if it isn't too hard. Any ideas how it could be accomplished?


You should be able to use a dictionary with a custom comparer that uses Type.IsAssignableFrom to compare the keys.

Update: As Qwertie pointed out, this doesn't work because you can't implement a repeatable hash code calculation based on a type, its interfaces, and ancestor classes. His answer provides a possible solution by repeatedly doing hash table look ups for the type, interfaces, and ancestor classes until it finds a match.

The only problem with that solution is that you don't have any way to specify which match to take when there are multiple matches. If you need that flexibility and control, I suggest you consider the chain-of-responsibility design pattern. Each transformer could be a link in the chain, and it's responsible for determining whether it can be applied to the object. If not, it passes the request to the next link. The order of transformers in the chain determines priority. You lose the speed of a hash table, but you were losing some of that speed anyway because of multiple look ups.


It occurs to me that the dictionary setter doesn't have different semantics from an ordinary dictionary, so one approach is to use a standard dictionary with specialized lookup:

public class TypeDictionary<TValue> : Dictionary<Type, TValue>
{
    public new TValue this[Type key]
    {
        get {
            TValue value;
            if (TryGetValue(key, out value))
                return value;
            throw new KeyNotFoundException("Not found: " + key.Name);
        }
    }
    public new bool TryGetValue(Type key, out TValue value)
    {
        if (base.TryGetValue(key, out value))
            return true;

        Type[] interfaces = key.GetInterfaces();
        for (int i = 0; i < interfaces.Length; i++)
            if (base.TryGetValue(interfaces[i], out value))
                return true;

        Type @base = key.BaseType;
        if (@base != null && TryGetValue(@base, out value))
            return true;

        return false;
    }
}

Note that if a class B derives from class A and interfaces IA and IB, and there is a value assigned to each of those types, it's ambiguous: should the value for A, IA, or IB be returned? The above implementation chooses the first interface it finds, and only if no interfaces are found, does it look for the base class.

I have no idea how good the performance of this dictionary is. If GetInterfaces() or the BaseType property is slow, it'll make lookup performance pretty bad (whenever the exact type you request is not in the dictionary).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜