Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a generic type-constraint for "where NOT derived from"?

Tags:

c#

generics

We can specify a "derived from" constraint on generic type parameters like this:

class Bar<T> where T : IFooGenerator

Is there a way to specify NOT derived from?


My use-case: I have a bunch of FooGenerators that are parallelizable, with the same parallelization code for each, but we don't want them to always be parallelized.

public class FooGenerator : IFooGenerator
{
    public Foo GenerateFoo() { ... }
}

Thus, I create a generic container class for generating Foo in parallel:

public class ParallelFooGenerator<T> : IFooGenerator where T : IFooGenerator
{
    public Foo GenerateFoo()
    {
        //Call T.GenerateFoo() a bunch in parallel
    }
}

Since I want FooGenerator and ParallelFooGenerator<FooGenerator> to be interchangeable, I make ParallelFooGenerator : IFooGenerator. However, I clearly don't want ParallelFooGenerator<ParallelFooGenerator> to be legal.

So, as an auxiliary question, is there perhaps a better way to design this if "not derived from" constraints are impossible?

like image 988
BlueRaja - Danny Pflughoeft Avatar asked Jun 25 '12 18:06

BlueRaja - Danny Pflughoeft


Video Answer


3 Answers

You could use something like the following:

public interface IFooGenerator
{
    Foo GenerateFoo();
}

interface ISerialFooGenerator : IFooGenerator { }

interface IParallelFooGenerator : IFooGenerator { }

public class FooGenerator : ISerialFooGenerator
{
    public Foo GenerateFoo()
    {
        //TODO
        return null;
    }
}

public class ParallelFooGenerator<T> : IParallelFooGenerator
    where T : ISerialFooGenerator, new()
{
    public Foo GenerateFoo()
    {
        //TODO
        return null;
    }
}
like image 96
Servy Avatar answered Nov 03 '22 00:11

Servy


ParallelFooGenerator<ParallelFooGenerator> already isn't possible, because ParallelFooGenerator is a generic type and you didn't specify a generic argument.

For example, ParallelFooGenerator<ParallelFooGenerator<SomeFooGenerator>> is possible -- and would allowing such a type really be that bad?

like image 29
cdhowie Avatar answered Nov 03 '22 01:11

cdhowie


The simple answer is no.

The long answer (still no):

Microsoft puts it well in their explanation of type constrains: "The compiler must have some guarantee that the operator or method it needs to call will be supported by any type argument that might be specified by client code."

The fundamental purpose of constraints is not to prohibit certain types from being used, but rather to allow the compiler to know what operators or methods are supported. You can, however, check if a type implements/inherits a specific interface/base class at run-time and throw an exception. With that, though, you will not be able to get a design-time error from intellisense.

I hope this helps.

like image 32
Steve Konves Avatar answered Nov 03 '22 00:11

Steve Konves