Reputation: 6669
As per the title, is it possible to declare type-negating constraints in c# 4 ?
The use-case of interest was to allow the following overloads to co-exist
void doIt<T>(T what){}
void doIt<T>(IEnumerable<T> whats){}
At the moment there is ambiguity because T
in the first method could be an IEnumerable<>
(so I would like to specify that T
should NOT be IEnumerable
)
Upvotes: 80
Views: 28874
Reputation: 591
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 expected 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>());
}
Upvotes: 8
Reputation: 5048
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)
{
}
Upvotes: 0
Reputation: 39
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.
Upvotes: 3
Reputation: 30666
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;
}
Upvotes: 5
Reputation: 49013
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.
Upvotes: -4
Reputation: 3355
No, but it would be possible to check with an "is" and then handle it appropriately...
Upvotes: 0