通用 NOT 约束 where T : !IEnumerable

发布于 2024-12-24 22:37:59 字数 303 浏览 1 评论 0原文

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

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

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

目前存在歧义,因为第一个方法中的 T 可能是 IEnumerable<> (所以我想指定 T 不应该是 IEnumerable

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)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

驱逐舰岛风号 2024-12-31 22:37:59

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

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

蔚蓝源自深海 2024-12-31 22:37:59

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

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

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

doIt(new List<T>());

但是它< strong>实际上引用了第二个

一种解决方案是像这样强制转换参数:

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

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

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

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>());
}
罪歌 2024-12-31 22:37:59

据我所知,这是不可能的。

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

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

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

    // ...

    return true;
}

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;
}
゛时过境迁 2024-12-31 22:37:59

其用途之一是选项类型。

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

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

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.

锦欢 2024-12-31 22:37:59

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

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

甜心 2024-12-31 22:37:59

据我所知,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)
    {

    }

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

    }
趴在窗边数星星i 2024-12-31 22:37:59

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

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文