generic NOT constraint where T : !IEnumerable

C#.NetGenericsIenumerable

C# Problem Overview


As per the title, is it possible to declare type-negating constraints in c# 4 ?

C# Solutions


Solution 1 - C#

No - there's no such concept either in C# or in the CLR.

Solution 2 - C#

I found my self trying to implement the same case mentioned in the comments:

void doIt<T>(IEnumerable<T> what) { }
void doIt<T>(T whats) { }

I excepted the following code to reference the first method:

doIt(new List<T>());

But it actually references the second one.

One solution is to cast the argument like this:

doIt(new List<T>().AsEnumerable<T>());

The cast could be hidden by another overload:

void doIt<T>(List<T> whats) {
    doIt(whats.AsEnumerable<T>());
}

Solution 3 - C#

As far as I know it is not possible to do that.

What you can do is some runtime checking:

public bool MyGenericMethod<T>()
{
    // if (T is IEnumerable) // don't do this

    if (typeof(T).GetInterface("IEnumerable") == null)
        return false;

    // ...

    return true;
}

Solution 4 - C#

one use for this would be an option type.

public class Option<A,B> 
where A : !B
where B : !A
{
    private readonly A a;
    private readonly B b;

    private Option(){}

    public Option(A a) 
    {
        this.a = a
    }

    public Option(B b)  
    {
        this.b = b
    }
} 

runtime checking would of course work but you wouldn't have the benefit of type checking at compile time.

Solution 5 - C#

No, but it would be possible to check with an "is" and then handle it appropriately...

Solution 6 - C#

As far as I know a Not contraint is not possible. You CAN use base classes and/or Interfaces to constrain a Generic. Faced with a similar problem leading to runtime failures, I implemented an interface on the classes the Generic was to handle:

public interface IOperations
{

}

public static T GenericOperationsFactory<T>(ILogger loggerInstance, ref ExecutionContext executionContext) 
        where T: IOperations
{
    var operationsContext = Factories.OperationsContextFactory(loggerInstance, ref executionContext);

    var operations = typeof(T).GetConstructor(new[] { typeof(OperationsContext) }).Invoke(new object[] { operationsContext });

    return (T)operations;
}

public abstract class OperationsBase:IOperations
{
    protected OperationsContext Context { get; set; }

    public OperationsBase(OperationsContext context)
    {
        Context = context;
    }
...

public class ListsOperations : OperationsBase
{
    public ListsOperations(OperationsContext context) :
        base(context)
    {

    }

alternatively:

public static T GenericOperationsFactory<T>(ILogger loggerInstance, ref ExecutionContext executionContext) 
        where T: OperationsBase
{
    var operationsContext = Factories.OperationsContextFactory(loggerInstance, ref executionContext);

    var operations = typeof(T).GetConstructor(new[] { typeof(OperationsContext) }).Invoke(new object[] { operationsContext });

    return (T)operations;
}

public abstract class OperationsBase
{
    protected OperationsContext Context { get; set; }

    public OperationsBase(OperationsContext context)
    {
        Context = context;
    }
...

public class ListsOperations : OperationsBase
{
    public ListsOperations(OperationsContext context) :
        base(context)
    {

    }

Solution 7 - C#

You use a constraint so you can ensure the type you use has some properties/methods/... you want to use.

A generic with a type-negating constraint doesn't make any sense, as there is no purpose to know the absence of some properties/methods you do not want to use.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionCelView Question on Stackoverflow
Solution 1 - C#Jon SkeetView Answer on Stackoverflow
Solution 2 - C#Ricardo ValenteView Answer on Stackoverflow
Solution 3 - C#Didier GhysView Answer on Stackoverflow
Solution 4 - C#DavidView Answer on Stackoverflow
Solution 5 - C#JayView Answer on Stackoverflow
Solution 6 - C#jlo-gmailView Answer on Stackoverflow
Solution 7 - C#ken2kView Answer on Stackoverflow