views:

395

answers:

5

Notice the following code. The offending line has been commented out.

interface I<R> { }

class C : I<int> { }

class Program
{
    private static void function<T, R>(T t) where T : class, I<R>
    {
    }

    static void Main(string[] args)
    {
        // function(new C()); // wont compile
        function<C, int>(new C());
    }
}

I believe type inference should figure out the type because the argument T provides the first type, while I<R> provides the second type.

Is there a way to redesign the function so that the callers may not have to specify the types?

+7  A: 

Not if you want to keep all the constraints. However, this should serve equally well, unless you have a specific reason to forbid value types:

private static void function<R>(I<R> t)
Vojislav Stojkovic
+1  A: 

No, C# doesn't support this kind of inference.

Use directly the interface and find the type with get type..

private static void function<R>(I<R> t)
{
   Type typeofT = typeof(T);
}

cannot do better.

If you need to call another generic method with T, you can build a generic call through reflection using typeofT Type.

Think Before Coding
Did you mean t.GetType()? T is no longer a type parameter in your modified method.
Jon Skeet
+3  A: 

There are various ways you could add extra rules to type inference - bits of logic that a human can apply but which the compiler (obeying the language spec) doesn't.

Before you suggest that the language really should be updated to make type inference work more flexibly though, I strongly suggest that you read the existing spec. If you can understand that sufficiently easily that you still think it's worth making it even more complicated, post a feature request on Connect - but personally I think it's quite complicated enough already. I would say that it's a lot better than it was in C# 2.0.

To put forward the opposing view, however - several languages (particularly functional ones) have more powerful type inference mechanisms. There are always pros and cons here - I believe one of the benefits of the current inference system in C# is that it always makes progress or stops, for instance - Eric Lippert's blog has more information on this and a number of other type inference issues.

Jon Skeet
+3  A: 
class D : I<int>, I<string> { }
//
function<D, int>(new D());
function<D, string>(new D());
//is R int or string?
function(new D());
David B
Yes, but the spec *could* have a special case which recognises that C *only* implements I<int>. It's all doable - but it makes the language more complicated.
Jon Skeet
Sure, but if I modify C later to add I<string>, then I would break that inference... break would be far from the change in source... bad scenario.
David B
In this case it could report an ambiguity (you should add a cast for disambiguation) but accept the single case.
Think Before Coding
If you cast to I<int>, you will not conform to the class restriction.
David B
I think it should report an ambiguity if it's ambiguous, but otherwise use the information at its disposal. The workaround for ambiguity is to specify the types (as in David B's snippet). I don't buy this "break far away from source" problem - all programming languages that support reuse of any kind have the ability to let you make a change in one location that breaks code in a thousand other distant locations.
Daniel Earwicker
@David B: Yes it would. “class” in a generic type parameter constraint means “must be a reference type”. Interfaces are reference types. (I tried it and the compiler accepts it as I expected.)
Timwi
A: 

C# does not support this kind of type inference. Consider this case which adds a bit of ambiguity to the problem.

class Other : I<int>, I<Student>{ ... }
void Example(){
  function(new D());
}

In this case there is an ambiguity as to which I should be chosen.

If you look forward to C# 4.0 the problem only increases with the new variance features they are adding.

JaredPar