3

Working with C# Generics you can have a class like this:

class Foo<T> where T:new() {}

Which means that the type T should have a constructor without parameters. It would be nice if we could have:

class Foo<T> where T : new(string)
{
    private T CreateItem()
    {
        string s="";
        return new T(s);
    }
}

Is there any reason that Microsoft haven't added this feature to the language?

Mark Cidade
  • 98,437
  • 31
  • 224
  • 236
Ariel
  • 1,641
  • 1
  • 18
  • 27
  • 1
    I would say this is very much related to this: http://stackoverflow.com/questions/619856/interface-defining-a-constructor-signature – Cade Roux Aug 15 '11 at 15:52
  • "We don't need to provide reasons for features to not be included. Rather, features must be justified on a cost-benefit basis." -- from http://stackoverflow.com/questions/3270463/why-c-does-not-support-multiple-inheritance/3270466#3270466 – stuartd Aug 15 '11 at 15:54

3 Answers3

11

Is there any reason that Microsoft haven't added this feature to the language?

The feature you describe is a specific case of the of the more general feature "allow a constraint that requires a particular method to exist". For example, you might say:

void M<T>(T t) where T has an accessible method with signature double Foo(int)
{
    double x = t.Foo(123);
}

We don't have that feature in C# because features have to be justified by a cost-benefit analysis. That would be a pretty expensive feature from both a design and implementation point of view -- a feature that would drive requirements onto not just C# but every .NET language. What's the compelling benefit that justifies the feature?

Moreover: suppose we did design that feature. How would it be implemented efficiently? The constraints in the generic type system have been carefully designed so that the jitter can generate efficient code once that can then be shared for every reference type. How would we generate efficient code for arbitrary method pattern matching? That sort of efficient dispatch is pretty straightforward when the method's slot can be known at compile time; with this feature we would no longer have that advantage.

The feature you want is the same feature, just with the kind of method restricted to a constructor.

Remember, the purpose of generics is to let you write generically typed code. If you're requiring constraints that are more specific than things that can be captured in the type system then you might be trying to abuse generics.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • 1
    if this is so hard, then why allow a parameterless constructor. – Ariel Aug 15 '11 at 16:28
  • 2
    @Ariel: The answer to your question is straightforward: **the cost of that much smaller feature is justified by the benefit it confers**. – Eric Lippert Aug 15 '11 at 16:45
  • Besides, there already exists a good workaround: Create an interface. More plumbing for sure, but it's not a hack or otherwise dodgy thing. And there are plenty of Interfaces with only 1 or 2 methods, and plenty of classes that implement 6 or more interfaces. – Michael Stum Aug 16 '11 at 04:12
  • 2
    @Michael: That's the one gotcha. An interface works fine for the general problem--- _except_ for the contructor. You can't put a .ctor into an interface. – Greg D Aug 16 '11 at 13:38
  • 2
    To answer your question on how to implement it efficiently, one approach (taken by F#, which does allow such constraints) is to inline a type-specific version of the code at each call-site, losing the benefit of sharing. – kvb Aug 16 '11 at 16:05
  • Nowadays we don't really need this feature anymore -- casting to `dynamic` lets you do it without needing explicit language support. Of course it probably is less efficient than it would be if the language and/or CLR had support for it. – Gabe Aug 18 '11 at 04:28
  • Eric, do I understand correctly from you asnwer that jitter works with opened generics?! But how? I mean this phrase "so that the jitter can generate efficient code once that can then be shared for every reference type" And why only reference type? – Pavel Voronin Jul 19 '13 at 18:09
  • 1
    @voroninp: If you have a method `M()` and you call `M` and `M`, the jitter only generates the machine code *once*. Do you see why it can safely do so? All references are the same size, and all the virtual method calls are on the same slots. The only things you have to fix up dynamically are things like `x is T` and other type tests, but those are easily parameterized. – Eric Lippert Jul 19 '13 at 18:22
  • @Eric. Never thought of that. Thanks. I believe the questions "Why is some feature not implemented?" should be read as "I'd like to know what were the reasons of the team when designing the feature in one way and not the other one? " And it's very diffiuclt to guess the motivations without deep knowledge and expertise. – Pavel Voronin Jul 19 '13 at 18:32
7

Rather than try to guess why Microsoft decided on a particular implementation, here's a workaround for you, using the factory pattern

public interface IFactory<T>
{
   T CreateItem(string s);
}

class Foo<TFactory,T> where TFactory : IFactory<T>, new()
{
    private T CreateItem()
    {
        var factory = new TFactory();
        string s="";
        return factory.CreateItem(s);
    }
}

Using this pattern, say you have a class Bar which has a constructor taking a single string:

public class Bar
{
   public Bar(string laa)
   {}
}

You just need a BarFactory which implements IFactory<Bar>

public class BarFactory : IFactory<Bar>
{
   public BarFactory () {}
   public Bar CreateItem(string s)
   {
      return new Bar(s);
   }
}

Now you can use that factory with Foo

var foo = new Foo<BarFactory,Bar>(); // calls to CreateItem() will construct a Bar
Jamiec
  • 133,658
  • 13
  • 134
  • 193
  • the factory pattern is a good patter and this is a good use of it, but this not the answer my question. Having the T:new() specification can't solve all scenarios. And when you have classes with multiple parameters it gets dirty. Usually i do something like this, and lately i was wondering why is this not part of the language? thats the question. – Ariel Aug 15 '11 at 16:06
  • @Ariel - fair enough, but a) this might help someone else and b) there is no valid answer to your question. Plus c) This could be extended to provide any combination of parameters if a more specific name is chosen for `IFactory`. – Jamiec Aug 15 '11 at 16:09
1

The solution I adopted when I wanted a generic function that invoked a constructor with arguments was to use reflection to find and invoke it.

Given that I had control of both the generic, and all the classes it was implemented over (and this function was the only place those classes were constructed), I think I might have been better to give the classes a default constructor and added an Initialize method in the interface they all implemented.

(A solution that allowed adding static methods in general to an interface would be ideal.)