0

Consider the following static generic method:

public class Foo
{
    public static void Test<T>(T arg)
    where T : FrameworkElement
    {
    }
}

I can simply call it like below and T will be implied to be a Button from the passed-in argument:

var myButton = new Button();
Foo.Test(myButton);

However, for the following generic class...

public class Laa<T>
where T : FrameworkElement
{
    public Laa(T element)
    {
    }
}

This code won't compile.

var myButton = new Button();
var laa = new Laa(myButton);

Instead, I have to explicitly provide the type like so.

var myButton = new Button();
var laa = new Laa<Button>(myButton);

I thought T would be implied from the provided argument but that doesn't seem to be the case.

I suspect the reason is because there is no class Laa--the class is actually Laa<Button>--so it doesn't know what to construct, but that's just a guess.

Even so, isn't there enough information for the compiler to figure this out? There is no class Laa but there is a generic Laa<T> which would be satisfied with the provided argument.

Mark A. Donohoe
  • 28,442
  • 25
  • 137
  • 286
  • It's a known limitation of C# compiler. There were some plans to fix it in VS2015 but the feature was cut. It might get fixed sometime in the future. – MarcinJuraszek Oct 11 '15 at 18:39
  • Probably the best explanation about the type inference in constructors can be found at this post - http://stackoverflow.com/a/3570360/247656 – Lukas Kabrt Oct 11 '15 at 18:52
  • A nice workaround is to use a static factory method in a non-generic class, like `Tuple.Create()` – Jakub Lortz Oct 11 '15 at 18:53

1 Answers1

0

That's OK. You always have to declare a generic type in constructor. The first example calls a static method, not class. You can never call a class. The second example calls a constructor of the class. Instantiation of a generic class requires generic type declaration.

Consider this:

public class Laa<T>
where T : FrameworkElement
{
    public Laa(T element)
    {
    }

    public void Foo<U>(U element)
    {
    }
}

var x = new Laa<Button>(button);
x.Foo(button);

In this case, Foo is a method and you don't have to declare the generic part of the method. Methods can deduce the generic types. Constructors can't.

Nytmo
  • 71
  • 1
  • 12
  • I don't think that's a proper example because 'Foo' in your code is *not* a method as you state. There's no return type--or void--which is required for a method. You've shown a mis-named constructor. Also, since you've already defined 'T' via the constructor, even if that were a method, it's value is *not* implied when calling 'Foo' since it had already been typed prior. – Mark A. Donohoe Oct 11 '15 at 18:45
  • In your example `Foo` "knows" the type because it is called on an instance of `Laa – juharr Oct 11 '15 at 18:47
  • Sorry, my bad. Just a typo. Of course, there should have been a return type/void. – Nytmo Oct 11 '15 at 18:48
  • @juharr Yes, but that's simply the same as the 'static' example. Simply said, constructors cannot induce generic types, methods can. We can argue about it but sadly that's everything we can do about it. – Nytmo Oct 11 '15 at 18:52
  • I'm just saying that in your example the method is not using inferred typing because the generic type is on the class which is determined when the class is created not when the method is called. In short your `Foo` method is not generic, the class that contains it is. – juharr Oct 11 '15 at 19:25