Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't C# infer my generic types?

I'm having lots of Funcy fun (fun intended) with generic methods. In most cases C# type inference is smart enough to find out what generic arguments it must use on my generic methods, but now I've got a design where the C# compiler doesn't succeed, while I believe it could have succeeded in finding the correct types.

Can anyone tell me whether the compiler is a bit dumb in this case, or is there a very clear reason why it can't infer my generic arguments?

Here's the code:

Classes and interface definitions:

interface IQuery<TResult> { }  interface IQueryProcessor {     TResult Process<TQuery, TResult>(TQuery query)         where TQuery : IQuery<TResult>; }  class SomeQuery : IQuery<string> { } 

Some code that does not compile:

class Test {     void Test(IQueryProcessor p)     {         var query = new SomeQuery();          // Does not compile :-(         p.Process(query);          // Must explicitly write all arguments         p.Process<SomeQuery, string>(query);     } } 

Why is this? What am I missing here?

Here's the compiler error message (it doesn't leave much to our imagination):

The type arguments for method IQueryProcessor.Process<TQuery, TResult>(TQuery) cannot be inferred from the usage. Try specifying the type arguments explicitly.

The reason I believe C# should be able to infer it is because of the following:

  1. I supply an object that implements IQuery<TResult>.
  2. That only IQuery<TResult> version that type implements is IQuery<string> and thus TResult must be string.
  3. With this information the compiler has TResult and TQuery.
like image 736
Steven Avatar asked Dec 14 '11 20:12

Steven


People also ask

Why there is no string in C?

Both Java and Python have the concept of a "string", C does not have the concept of a "string". C has character arrays which can come in "read only" or manipulatable. A character array is a sequence of contiguous characters with a unique sentinel character at the end (normally a NULL terminator '\0' ).

What does C++ have that C doesnt?

C++ was developed by Bjarne Stroustrup in 1979. C does no support polymorphism, encapsulation, and inheritance which means that C does not support object oriented programming. C++ supports polymorphism, encapsulation, and inheritance because it is an object oriented programming language.

Why C has no exception handling?

As such, C programming does not provide direct support for error handling but being a system programming language, it provides you access at lower level in the form of return values. Most of the C or even Unix function calls return -1 or NULL in case of any error and set an error code errno.

Why is C not outdated?

The C programming language doesn't seem to have an expiration date. It's closeness to the hardware, great portability and deterministic usage of resources makes it ideal for low level development for such things as operating system kernels and embedded software.


2 Answers

A bunch of people have pointed out that C# does not make inferences based on constraints. That is correct, and relevant to the question. Inferences are made by examining arguments and their corresponding formal parameter types and that is the only source of inference information.

A bunch of people have then linked to this article:

https://docs.microsoft.com/en-us/archive/blogs/ericlippert/c-3-0-return-type-inference-does-not-work-on-method-groups

That article is both out-of-date and irrelevant to the question. It is out-of-date because it describes a design decision we made in C# 3.0 which we then reversed in C# 4.0, mostly based on the response to that article. I've just added an update to that effect to the article.

It is irrelevant because the article is about return type inference from method group arguments to generic delegate formal parameters. That is not the situation the original poster asks about.

The relevant article of mine to read is rather this one:

https://docs.microsoft.com/en-us/archive/blogs/ericlippert/constraints-are-not-part-of-the-signature

UPDATE: I have heard news that C# 7.3 has slightly changed the rules for when constraints are applied, making the above ten-year-old article no longer accurate. When I have time I'll review the changes my former colleagues have made and see if it is worthwhile to post a correction on my new blog; until then, use caution and see what C# 7.3 does in practice.

like image 97
Eric Lippert Avatar answered Oct 11 '22 11:10

Eric Lippert


C# will not infer generic types based on the return type of a generic method, only the arguments to the method.

It also doesn't use the constraints as part of the type inference, which eliminates the generic constraint from supplying the type for you.

For details, see Eric Lippert's post on the subject.

like image 42
Reed Copsey Avatar answered Oct 11 '22 10:10

Reed Copsey