通用 NOT 约束,其中 T : !IEnumerable

问题描述 投票:0回答:7

根据标题,是否可以在 c# 4 中声明类型否定约束?

感兴趣的用例是允许以下重载共存

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

目前存在歧义,因为第一种方法中的

T
可能是
IEnumerable<>
(所以我想指定
T
不应该是
IEnumerable

c# .net generics ienumerable
7个回答
60
投票

不 - 在 C# 或 CLR 中都没有这样的概念。


8
投票

我发现自己试图实现评论中提到的相同的情况

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

期望以下代码来引用第一种方法

doIt(new List<T>());

但它实际上引用了第二个

一个解决方案是cast这样的论点:

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

强制转换可能会被另一个重载隐藏:

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

5
投票

据我所知这是不可能的。

您可以做的是一些运行时检查:

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

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

    // ...

    return true;
}

4
投票

一个用途是选项类型。

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
    }
} 

运行时检查当然可以工作,但您不会享受到编译时类型检查的好处。


0
投票

不,但是可以用“is”进行检查,然后进行适当的处理...


-1
投票

据我所知,Not 约束是不可能的。您可以使用基类和/或接口来约束泛型。面对导致运行时失败的类似问题,我在通用要处理的类上实现了一个接口:

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)
    {

    }

或者:

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)
    {

    }

-4
投票

您使用约束,以便确保您使用的类型具有一些属性/方法/...您想要使用

具有类型否定约束的泛型没有任何意义,因为没有目的知道某些属性/方法的缺失你不想使用

© www.soinside.com 2019 - 2024. All rights reserved.