5

I have a generic class named Manager<T>, and I want to create a dictionary that maps a type to an instance of the Manager class of this type. I thought about creating a Dictionary class that derives from Dictionary, but overriding all of its methods seems overkill. Ideas? Thanks.

  • 2
    It seems you want a `Dictionary>` or something along that instead if you actually intend to use types as keys. – BoltClock Dec 24 '11 at 11:40
  • You need to have a command factory that will provide the correct Manager class to work on the type, assuming that the types can't implement a common interface. – Mark Dickinson Dec 24 '11 at 11:52
  • Im pretty sure C# generic syntax doesnt support this in this instance, however this is the ideal here – undefined Dec 24 '11 at 11:54
  • 1
    C# only seems to supports the empty <> inside a typeof statement ie typeof(List<>) is valid however List> – undefined Dec 24 '11 at 12:28
  • the trouble with this is that what you really want to do is to create a dictionary to map Type to Manager isnt supported by the language. ie you cant include typeof in the generic header. eg Dictionary> isnt actually syntactically valid even though its kinda the outcome you would like here – undefined Dec 24 '11 at 13:05
  • Preserving the genericness of the Manager internally doesn't matter here, it seems to me. As long as the type-unsafity is kept enclosed in the small area of this Dictionary wrapper, everything is okay. – Dykam Dec 24 '11 at 13:30

4 Answers4

2

Assuming that your dictionary needs to hold managers with mixed type arguments, you can implement an IManager interface in Manager<T>, make a Dictionary<Type,IManager>, and add a generic wrapper to cast instances back to Maanger<T>, like this:

interface IManager {
    // Properties and methods common to all Maanger<T>, regardless of T
}

class Manager<T> : IManager {
}

class Main {
    private readonly IDictionary<Type,IManager> managers =
        new Dictionary<Type,IManager>();

    bool TryGetManager<T>(Type key, out Manager<T> manager) {
        IManager res;
        return managers.TryGetValue(key, out res) ? ((Manager<T>)res) : null;
    }
}
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • This doesnt preserve the generic type from the dictionary does it? – undefined Dec 24 '11 at 11:54
  • @LukeMcGregor If I understood the question correctly, the idea was to store generic instances in a dictionary; having a generic dictionary was not a goal in itself. To that end, the sample does what the OP wants: he gets to look up a `Manager` by the `Type` of his `T`, getting a generic back. – Sergey Kalinichenko Dec 24 '11 at 11:59
  • You actually lose the genericness entirely with this, eg string DoSomething(T val) would be converted to string DoSomething(object val) by IManager and even if you actually make a generic version you have to preserve the object version for the sake of the interface. TBH IManager would be much better as a marker interface, at least then the only impact would be a cast on the way out of the dictionary. – undefined Dec 24 '11 at 12:09
  • @LukeMcGregor I think I know why you got confused: I declared `TryGetManager(Type,T manager)` instead of `TryGetManager(Type, Manager manager)`. I have now fixed it. The interface is non-essential to the solution: he might as well have `object` in the dictionary. – Sergey Kalinichenko Dec 24 '11 at 12:16
  • Dictionary isn't particularly nice as it doesn't ensure any type safety on the stored item – undefined Dec 24 '11 at 12:19
  • @LukeMcGregor Think about it carefully: there's absolutely nothing else it can do. Unless you add a common interface as I suggested, `System.Object` would be the only common ancestor type of all `Manager`. – Sergey Kalinichenko Dec 24 '11 at 12:26
  • 1
    Your solution would be much better if IManager was simply a marker interface ie empty, however it still kinda doesnt solve the problem – undefined Dec 24 '11 at 12:36
  • @LukeMcGregor Whether or not it should be a marker is up to the OP to decide. As far as solving the OP's problem, it's the *only* answer on the page that addresses the "create a dictionary that maps a type to an instance of the Manager class of this type" requirement. – Sergey Kalinichenko Dec 24 '11 at 12:42
2

i think this is a case generics doesnt support nicely, prehaps this is what you want. You will need to store managers internally to this, for the storage prehaps use a Dictionary<Type,Object> or Dictionary<Type,IManager> where IManager is a marker (empty) interface applied to Manager<T> You will then need to cast this to the type T provided before returning it. I cant think of a good way to access this via an indexer so this may be the best you can get to

public class ManagerDictionary{
    private Dictionary<Type, object> _managers = new Dictionary<Type, object>();

    public Manager<T> GetManager<T>()
    {
        if (_managers.ContainsKey(typeof(T)))
        {
            return _managers[typeof(T)] as Manager<T>;
        }
        throw new ArgumentException("No manager of " + typeof(T).Name + " could be found");
    }

    public void AddManager<T>(Manager<T> manager)
    {
        _managers.Add(typeof(T),manager);
    }
}
undefined
  • 33,537
  • 22
  • 129
  • 198
  • How does this address the "create a dictionary that maps a type to an instance of the Manager class of this type" requirement from the OP? – Sergey Kalinichenko Dec 24 '11 at 12:42
  • It doesnt create an IDictionary, what it does do is create a way of getting a provided instance of a specific Manager for the type T which is what i understand the intent of the question to be – undefined Dec 24 '11 at 12:47
  • I think the header of the OP is misleading. Inside the post he clearly states: "I want to create a dictionary that maps a *type* to an instance of the *Manager class of this type*.", while the title suggests that he wants to map *an instance of type T* to an instance of the Manager class of this type. The former makes sense (and is in fact a common problem to solve), while the later does not make much sense outside of rather contrived examples. – Sergey Kalinichenko Dec 24 '11 at 12:52
  • I think the title is a little misleading – undefined Dec 24 '11 at 13:02
  • OK, now your solution looks almost like mine :):):) – Sergey Kalinichenko Dec 24 '11 at 13:07
  • I suppose it is similar... prehaps i didnt fully understand what you were getting at. I do however think that its important not to put any content into IManager if you have it as that will break type safety. I also think its important to wrap this in a class to group it together. Otherwise yes they are very similar so downvote removed – undefined Dec 24 '11 at 13:18
1

For this to work you really need to have an interface that T derives from. Then your manager class can work with whatever concrete T you pass in.

class Manager<T> where T: IMyClass

This is good practice as the methods on the interface are what make T generic.

For more ideas you could look at the Command Pattern

You are going to have some sort of switch or dictionary to maintain, but you should be able to get a good solution.

Mark Dickinson
  • 6,573
  • 4
  • 29
  • 41
0

I think this code would make it:

class ManagerDictionary<T> : Dictionary<T, Manager<T>> {

}
Yogu
  • 9,165
  • 5
  • 37
  • 58
  • This does not address the "create a dictionary that maps a type to an instance of the Manager class of this type" requirement from the OP. The headline is misleading, because Dictionary> is certainly *not* what the OP is looking for. – Sergey Kalinichenko Dec 24 '11 at 12:44
  • This will only map a single type to a manager of that type. ie it will allow mapping the string "hello" to an instance of Manager which isnt really the intention – undefined Dec 24 '11 at 13:21