简体   繁体   English

适用于IEnumerable的扩展方法 <T> 和IQueryable <T> ?

[英]Extension method that works on IEnumerable<T> and IQueryable<T>?

I want an extension method that works on both my List and IQueryable. 我想要一个适用于我的List和IQueryable的扩展方法。 The extension methods below accomplish this, but then if I add another identical extension method, but on a different totally unrelated type I get ambiguous call compile errors. 下面的扩展方法实现了这一点,但是如果我添加另一个相同的扩展方法,但是在不同的完全不相关的类型上,我会得到不明确的调用编译错误。 Why is that? 这是为什么? Isn't the compiler smart enough to know which extension method works? 编译器是否足够聪明,无法知道哪种扩展方法有效? I mean, only one of these calls is valid, why can't the compiler tell? 我的意思是,这些调用中只有一个是有效的,为什么编译器无法告诉? Thanks a lot! 非常感谢!

class ClassA
{
  public bool IsActive{ get; set;}
}

class ClassB
{
  public bool IsActive { get; set;}
}


// then here are my extensions

public static T IsActive<T>(this T enumerableOrQueryable, bool isActive)
  where T : IEnumerable<ClassA>
{
  return (T)enumerableOrQueryable.Where(x => x.IsActive == isActive);
}

public static T IsActive<T>(this T enumerableOrQueryable, bool isActive)
  where T : IEnumerable<ClassB>
{
  return (T)enumerableOrQueryable.Where(x => x.IsActive == isActive);
}

The overload rules don't take account of the constraints on methods that it's considering - it determines which overload is best and then validates that the constraints match. 重载规则没有考虑它正在考虑的方法的约束 - 它确定哪个重载是最好的, 然后验证约束匹配。

The compiler is exactly following the rules of the C# specification. 编译器完全遵循C#规范的规则。

Related blog posts: 相关博文:

EDIT: Note that using an "enumerableOrQueryable" is always going to convert your lambda expression to a delegate, not an expression tree. 编辑:请注意,使用“enumerableOrQueryable” 总是将lambda表达式转换为委托,而不是表达式树。 So if you wanted it to perform the logic differently for a database, you'd need a change anyway. 因此,如果您希望它为数据库执行不同的逻辑,则无论如何都需要进行更改。

EDIT: Your idea also wouldn't work because you wouldn't get the same result type out anyway - if you call Where on a List<string> , the returned value isn't a List<string> . 编辑:你的想法行不通,因为你不会得到相同的结果类型 - 如果你Where List<string>上调用Where ,返回的值不是 List<string>

What you can do is this, if you can introduce a new interface to be implemented by both ClassA and ClassB: 如果您可以引入由ClassA和ClassB实现的新接口,那么您可以做到这一点:

public static IQueryable<T> IsActive<T>(this IQueryable<T> source, bool isActive)
    where T : ICanBeActive
{
    // Lambda converted to an expression tree
    return source.Where(x => x.IsActive == isActive);
}

public static IEnumerable<T> IsActive<T>(this IEnumerable<T> source,
    bool isActive) where T : ICanBeActive
{
    // Lambda converted to a delegate
    return source.Where(x => x.IsActive == isActive);
}

The compiler cannot resolve ambiguity from the generic constraints. 编译器无法解决通用约束中的歧义。 For your case, can't you just do something like this ? 对于你的情况,你不能只做这样的事情吗?

public static IEnumerable<ClassA> IsActive(this IEnumerable<ClassA> enumerableOrQueryable, bool isActive)
{
  return enumerableOrQueryable.Where(x => x.IsActive == isActive);
}

You can try something like this: 你可以尝试这样的事情:

public interface IActivatable
{
    bool IsActive { get; set; }
}

public class ClassA : IActivatable
{
    public bool IsActive{ get; set;}
}

public class ClassB : IActivatable
{
    public bool IsActive { get; set;}
}

public static class Ext
{
    public static IEnumerable<T> IsActive<T>(this IEnumerable<T> collection, bool isActive) where T : IActivatable
    {
        return collection.Where(x => x.IsActive == isActive);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM