I have a generic class A, and another class B that handles instances of A and contains some additional data. I need to have two separate classes. B can't inherit from A, because A has other derivatives, B needs to contain a reference to an A.
As a simple example, what I would like to write is this (dictionary is A, dicthandler is B):
class dicthandler<T> where T : Dictionary<Tk, Tv>
But it doesn't compile, I need to specify all type parameters:
class dicthandler<T, Tk, Tv> where T : Dictionary<Tk, Tv>
But I actually don't care what Tk and Tv is, so they are completely redundant, I just need T. Whenever I want to create a new instance, I need to specify all type parameters for the constructor, which hurts me.
So clearly I need some tricks. Any ideas?
Nope, there's no way of doing this. Any instance of DictHandler must know the exact type of T, including the type of TKey and TValue.
You can use type inference to reduce how often you need to explicitly specify type arguments though, if you actually have an instance of the relevant dictionary. For example:
public static class DictHandler
{
public static DictHandler<T, TKey, TValue> CreateHandler<T, TKey, TValue>
(T dictionary1, Dictionary<TKey, TValue> dictionary2)
where T : Dictionary<TKey, TValue>
{
return new DictHandler<T, TKey, TValue>();
}
}
public class DictHandler<T, TKey, TValue> where T : Dictionary<TKey, TValue>
{
}
Then create it like this:
Dictionary<string, int> dict = new Dictionary<string, int>();
var handler = DictHandler.CreateHandler(dict, dict);
I believe the reason you have to have the two parameters is so that the arguments (which are all that gets used in type inference) end up corresponding with parameters which directly mention the type parameters. I'm not entirely sure though - and this is certainly somewhat ugly.
Another alternative is to create a base type or base interface for A which isn't generic. For example, in this case (assuming we could control Dictionary) we'd create:
public interface INonGenericDictionary
{
// Members which don't rely on the type parameters
}
public class Dictionary<TKey, TValue> : INonGenericDictionary
{
...
}
then
public class DictHandler<T> where T : INonGenericDictionary
{
...
}
We can't really tell whether that's suitable in your case, but it may be.
When it comes to object construction, current C# demands that you be very specific. This seems like an unlikely thing to create very often, though, so you could just create a CreateDictHandler type from the current type's type-parameters:
private dicthandler<T, Tk, Tv> CreateDictHandler() {...}
...
var handler = CreateDictHandler();
If the type-parameters are for the method you'll have to supply them for the constructor, but you can still use var on the variable declaration.
You may also find that in many cases too much generics is actually a bad thing. If it starts to get too gnarly, there are times when things like IDictionary (non-generic) are genuinely desirable.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With