Roslyn: Proposal: Extend generic type new() constraint with parameter types

Created on 12 Oct 2016  路  6Comments  路  Source: dotnet/roslyn

Background

Currently C# allows its users to apply the "new()" constraint on methods accepting a generic type to let the compiler know it has a parameter-less constructor.

The following example shows 2 'random generators' that implement the IRandom interface that are being created and then used to return data:

class Program
{
    static void Main(string[] args)
    {
        var randomData1 = CreateRandomData<FastRandom>(10);
        var randomData2 = CreateRandomData<CryptoRandom>(10);
    }

    public static IEnumerable<int> CreateRandomData<R>(int length) where R : IRandom, new()
    {
        var randomGenerator = new R();
        for (int i = 0; i < length; i++)
        {
            yield return randomGenerator.Next();
        }
    }
}

public interface IRandom
{
    int Next();
}

public class FastRandom : IRandom
{
    public FastRandom()
    {

    }

    public int Next()
    {
        return 0;
    }
}

public class CryptoRandom : IRandom
{
    public CryptoRandom()
    {

    }

    public int Next()
    {
        return 1;
    }
}

Problem

Currently it's not possible to provide a parameter (e.g. a seed) to the constructor of the 'to-be created' random generators. The current solutions would be:

  1. Use reflection to call the constructor and passing the argument to it. (Disadvantage: Not compile time safe)
  2. Use a factory and do a switch case on the different types of implementations of the IRandom interface. Then return a new instance of the found match. (Disadvantage: Need to extend Factory every time a new class implements IRandom)
  3. Implement an additional method on the interface (and thus implementing classes) Initialize(int seed); which will initialize the class and set it up. (Disadvantage: Having to do 2 method calls for something that's normally done in the constructor.)

Solution: parameterized new()

My proposed solution would be to also accept parameter types in the new() constraint. E.g. the new(int) in the following line of code:

public static IEnumerable<int> CreateRandomData<R>(int length) where R : IRandom, new(int)

This would make the complete solution look something similar to this:

class Program
{
    static void Main(string[] args)
    {
        var randomData1 = CreateRandomData<FastRandom>(10);
        var randomData2 = CreateRandomData<CryptoRandom>(10);
    }

    public static IEnumerable<int> CreateRandomData<R>(int length) where R : IRandom, new(int)
    {
        var randomGenerator = new R(50);
        for (int i = 0; i < length; i++)
        {
            yield return randomGenerator.Next();
        }
    }
}

public interface IRandom
{
    int Next();
}

public class FastRandom : IRandom
{
    private int seed;
    public FastRandom(int seed)
    {
        this.seed = seed;
    }

    public int Next()
    {
        return 0 + seed;
    }
}

public class CryptoRandom : IRandom
{
    private int seed;
    public CryptoRandom(int seed)
    {
        this.seed = seed;
    }

    public int Next()
    {
        return 1 + seed;
    }
}
Area-Language Design

Most helpful comment

Yeah, that's indeed one of the workaround you can use for now. However I would like to do this type safe at compile time :).

All 6 comments

This seems to be a duplicate of #2206 which is a shame because your version is also well-written. On the upside it's already in 1-Planning state :).

Ah :), well, my goal to get this implemented would still be resolved then.
Any idea how long it usually takes for an item to go from 1-Planning to Implemented / Released?

No idea. Let's say I wouldn't expect it next year.

@devedse i know this issue is old, but just in case you wanted to make this you can use (R)Activator.CreateInstance(typeof(R), length)

Yeah, that's indeed one of the workaround you can use for now. However I would like to do this type safe at compile time :).

This issue was moved to dotnet/csharplang#769

Was this page helpful?
0 / 5 - 0 ratings