Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

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?

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? – cdhowie Jun 25, 2012 at 18:18 No it's not possible - allowed constraints: msdn.microsoft.com/en-us/library/d5x73970.aspx – Slugart Jun 25, 2012 at 18:19 @cdhowie: Wow, derp, you're right. Well, that solves my problem :) But the question could still be useful to others! – BlueRaja - Danny Pflughoeft Jun 25, 2012 at 18:20 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; This is a better design imho. Adding an interface one level up rather than restricting inheritage one level down is way cleaner and easier to understand. Each interface and class makes sense on its own. – vidstige Jun 26, 2012 at 8:39 @cdhowie solved my problem, but I'm marking this correct as it answers the question in the title. Thanks! – BlueRaja - Danny Pflughoeft Jun 26, 2012 at 15:31

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?

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.

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.