6

I have the following method:

public TResult Get<TGenericType, TResult>()
                          where TGenericType : SomeGenericType<TResult>
                          where TResult : IConvertible {
   //...code that uses TGenericType...
   //...code that sets someValue...
   return (TResult) someValue;
}

Right now, a user of this method has to use it like this:

//Notice the duplicate int type specification
int number = Get<SomeGenericType<int>, int>();

Why do I have to specify TResult in the method defintion? The compiler already knows TResult since I specified it in TGenericType. Ideally (if the C# compiler was a little smarter), my method would look like this:

public TResult Get<TGenericType>()
                          where TGenericType : SomeGenericType<TResult>
                          where TResult : IConvertible {
   //...code that uses TGenericType...
   //...code that sets someValue...
   return (TResult) someValue;
}

So the user could just simply use it like this:

//Much cleaner
int number = Get<SomeGenericType<int>>();

Is there a way to do what I want to do?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
  • I think removing some qualifiers such as *stupid* from question description will help. – EFraim Jul 30 '09 at 19:28
  • It's the compiler that's stupid, right? ;) I removed the extraneous commentary. This is actually a reasonable question without it. – Rex M Jul 30 '09 at 19:29
  • Since you've been answered that there is no way to use just some of the type parameters, perhaps you should reformulate your question in terms of what you'd like to accomplish. As it stands, your question is "how do I make the C# compiler compile code that violates the definition of the C# language?" As such, it should be closed as "not a real question". – John Saunders Jul 30 '09 at 19:36
  • 1
    @John since many people do not know the c# spec by heart, it is reasonable to ask "is there a way to hint the compiler to do what I want" and an equally reasonably answer is "no, the c# spec does not allow that." – Rex M Jul 30 '09 at 19:38
  • What I want to accomplish has not changed. It just sucks that it's the way it is. I hope they change it in a future version of C#. –  Jul 30 '09 at 19:40
  • @Rex M: Ok, so maybe the current question should be rephrased along the lines of, "why doesn't this compile", with the answer being, "because it is not valid C#". Then, "how do I accomplish this" would be a second question. Good point. – John Saunders Jul 30 '09 at 19:42
  • @Hermann: That's not _what_ you wanted to accomplish, it's _how_ you wanted to accomplish it. I meant step back one and think what the goal was. However, @Rex M convinced me that should be a second question. – John Saunders Jul 30 '09 at 19:43
  • What I want to accomplish is to return 'someValue' as 'TResult', but I don't want the user have to know 'TResult' because 'TResult' will be specified by classes that derive from 'SomeGenericType'. –  Jul 30 '09 at 19:58

2 Answers2

8

The C# specification does not allow inferring half of type arguments. You should either let the compiler to infer all the type arguments (which is not always applicable, like in your case) or manually specify all of them.

UPDATE (reply to comment): While I'm not on the C# team to give an absolute answer to your question, my speculation is that the complexity of overload resolution (which is already mind-blowing; you know that if you read that section of C# specification) would increase significantly if they wanted to allow half of types to be inferred and half not (especially considering the fact that you can overload methods solely by the number of generic arguments).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Mehrdad Afshari
  • 414,610
  • 91
  • 852
  • 789
  • But why did they specify that in the C# specification? It's not like there is anything unsafe about it. –  Jul 30 '09 at 19:28
  • Look into some of the C++ rules, including partial specialization of templates and how access specifiers work. Usually things work smoothly, but there are gotchas lurking here and there. Since one of the ideas behind Java and C# was to avoid C++'s complication, accepting a little inconvenience instead, this is right in line. – David Thornley Jul 30 '09 at 19:36
1

It depends...

If you're just using SomeGenericType<TResult>, you can do:

public TResult Get<TResult>() where TResult : IConvertible {
    SomeGenericType<TResult> myInstance = ...
    //...code that sets someValue...
    return (TResult) someValue;
}

There isn't necessarily a way to put the first type in there, in this case. Since your example isn't passing in a SomeGenericType<TResult> explicitly as a parameter, it suggests this would be possible.

Otherwise, you need to completely specify all of your generic arguments. Unfortunately, that's just the way it is in C#.

Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • Sure, but I do need to use SomeGenericType in the method. I'll update my sample code to make that clear. –  Jul 30 '09 at 19:33
  • Yeah, but look at my code - as long as it's not passed in as a parameter to the method, you can use SomeGenericType in the method (ie: if you construct one in the method). Since you know TResult, this works fine. As I said - it can work in some cases... – Reed Copsey Jul 30 '09 at 19:40
  • Sorry, I meant I need to use TGenericType (see my updated sample code). –  Jul 30 '09 at 19:59