Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

getting rid of redundant type parameters

Tags:

c#

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?

like image 457
fejesjoco Avatar asked Dec 14 '25 10:12

fejesjoco


2 Answers

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.

like image 181
Jon Skeet Avatar answered Dec 17 '25 00:12

Jon Skeet


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.

like image 45
Marc Gravell Avatar answered Dec 16 '25 23:12

Marc Gravell



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!