适用于 IEnumerable的扩展方法和 IQueryable

发布于 2024-12-09 10:48:59 字数 724 浏览 0 评论 0原文

我想要一个适用于我的 List 和 IQueryable 的扩展方法。下面的扩展方法可以实现此目的,但是如果我添加另一个相同的扩展方法,但在不同的完全不相关的类型上,我会得到不明确的调用 编译错误。这是为什么?难道编译器不够聪明,知道哪种扩展方法有效吗?我的意思是,这些调用中只有一个是有效的,为什么编译器不能告诉呢?多谢!

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

I want an extension method that works on both my List and 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);
}

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

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

发布评论

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

评论(3

跨年 2024-12-16 10:48:59

重载规则不考虑它正在考虑的方法的约束 - 它确定哪个重载是最好的,然后验证约束是否匹配。

编译器完全遵循 C# 规范的规则。

相关博客文章:

编辑:请注意,使用“enumerableOrQueryable”总是会将您的 lambda 表达式转换为委托,而不是表达式树。因此,如果您希望它以不同的方式对数据库执行逻辑,那么您无论如何都需要进行更改。

编辑:你的想法也行不通,因为无论如何你都不会得到相同的结果类型 - 如果你在 List< 上调用 Where /code>,返回值不是 List

如果您可以引入一个由 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 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.

Related blog posts:

EDIT: Note that using an "enumerableOrQueryable" is always going to convert your lambda expression to a delegate, not an expression tree. 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>.

What you can do is this, if you can introduce a new interface to be implemented by both ClassA and 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);
}
束缚m 2024-12-16 10:48:59

编译器无法解决通用约束中的歧义。对于你的情况,你不能做这样的事情吗?

public static IEnumerable<ClassA> IsActive(this IEnumerable<ClassA> enumerableOrQueryable, bool isActive)
{
  return enumerableOrQueryable.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);
}
倾城花音 2024-12-16 10:48:59

你可以尝试这样的事情:

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

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