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

C# 适用于IEnumerable的扩展方法<;T>;和IQueryable<;T>;?,c#,generics,extension-methods,C#,Generics,Extension Methods,我想要一个对我的列表和IQueryable都有效的扩展方法。下面的扩展方法实现了这一点,但是如果我添加了另一个相同的扩展方法,但是在另一个完全不相关的类型上,我会得到不明确的调用 编译错误。为什么呢?编译器还不够聪明,不知道哪种扩展方法有效吗?我的意思是,这些调用中只有一个是有效的,为什么编译器不能告诉你呢?非常感谢 class ClassA { public bool IsActive{ get; set;} } class ClassB { public bool IsActive

我想要一个对我的列表和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);
}
A类
{
公共bool IsActive{get;set;}
}
B类
{
公共bool IsActive{get;set;}
}
//这是我的分机
public static T IsActive(此T可枚举或可查询,bool IsActive)
其中T:IEnumerable
{
返回(T)enumerableOrQueryable.Where(x=>x.IsActive==IsActive);
}
public static T IsActive(此T可枚举或可查询,bool IsActive)
其中T:IEnumerable
{
返回(T)enumerableOrQueryable.Where(x=>x.IsActive==IsActive);
}

编译器无法解决泛型约束的歧义。就你的情况而言,你就不能这样做吗

public static IEnumerable<ClassA> IsActive(this IEnumerable<ClassA> enumerableOrQueryable, bool isActive)
{
  return enumerableOrQueryable.Where(x => x.IsActive == isActive);
}
公共静态IEnumerable IsActive(此IEnumerable Enumerable或Queryable,bool IsActive)
{
返回enumerableOrQueryable.Where(x=>x.IsActive==IsActive);
}

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

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

相关博客帖子:

  • (我)
  • (埃里克·利珀特)
  • (我-真的很讨厌,但很有趣)
编辑:请注意,使用“enumerableOrQueryable”总是将lambda表达式转换为委托,而不是表达式树。因此,如果希望它以不同的方式为数据库执行逻辑,那么无论如何都需要进行更改

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

如果您可以引入一个新的接口来由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);
}
publicstaticiqueryable-IsActive(此IQueryable源,bool-IsActive)
T:我很活跃
{
//Lambda转换为表达式树
返回source.Where(x=>x.IsActive==IsActive);
}
公共静态IEnumerable IsActive(此IEnumerable源,
T:我是活跃的
{
//Lambda已转换为委托
返回source.Where(x=>x.IsActive==IsActive);
}

您可以尝试以下方法:

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);
    }
}
公共接口IActivatable
{
布尔是活动的{get;set;}
}
公共类ClassA:IActivatable
{
公共bool IsActive{get;set;}
}
公共类ClassB:IActivatable
{
公共bool IsActive{get;set;}
}
公共静态类Ext
{
公共静态IEnumerable IsActive(此IEnumerable集合,bool IsActive),其中T:IActivatable
{
返回集合。其中(x=>x.IsActive==IsActive);
}
}

为什么不直接使用IEnumerable而不是T?请注意,那些
中的
应该是
单个的
单个的或默认的
第一个
,或者
FirstOrDefault
取决于用法-
其中
用于返回多个匹配元素?我不能使用IEnumerable,因为我希望它们同时适用于List和IQueryable。例如,如果我通过IQueryable,那么我希望IQueryable成为返回类型。我明白了,谢谢。我不想在签名中指定IEnumerable,因为我希望传入的类型与传入的类型相同。此方法将始终返回IEnumerableThanks!这是一个快速的回答。我现在觉得自己很愚蠢。所以,除非我想确保我所有的扩展方法都有不同的名称,否则根本没有办法完成我想要做的事情?@funGhoul:好吧,你可以尝试一些类似我的“邪恶代码”版本的东西,但我不确定这是否对你有帮助。老实说,我想你会发现用不同的名字会更清楚。我还想到了一些别的东西…@funGhoul:更多问题和可能的解决方案,请参阅我的编辑。非常感谢!我会用我必须做的事情来编辑我的问题,以防有人在意。晚会迟到了,但IQueryable版本将不起作用(至少对于EF来说)。T也必须是类,否则表达式包含的强制转换会混淆底层提供程序。