开发者

Why C# don't accept constructor requirements with parameters on generics?

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?


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.


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


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.)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜