generic NOT constraint where T : !IEnumerable
C#.NetGenericsIenumerableC# 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.