无法返回 IEnumerable<TEnum> 代替 IEnumerable<T>



我写了这个 EnumHelper 方法

    public static IEnumerable<T> AsEnumerable<TEnum, T>(Func<TEnum, T> projection = null) where TEnum : struct
    {
        if (!typeof(TEnum).IsEnum)
            throw new InvalidOperationException("Type parameter TEnum must be an enum");
        if (projection == null)
            return Enum.GetValues(typeof (TEnum)).OfType<TEnum>();
        return Enum.GetValues(typeof (TEnum)).OfType<TEnum>().Select(projection);
    }

我在第一次返回时收到编译时错误。这将返回一个IEnumerable<TEnum>

错误 46 无法将类型 System.Collections.Generic.IEnumerable<TEnum> 隐式转换为 System.Collections.Generic.IEnumerable<T>

我对T没有任何约束,所以TTEnum更通用。在IEnumerable<out T> T是可变的,那么为什么我仍然得到错误?

方差仅在两种类型之间存在多态关系时才适用。在您的情况下,TEnumT 不限于相关,因此协方差不适用。

您可以通过将枚举成员直接强制转换为目标类型来轻松解决此问题:

if (projection == null)
    return Enum.GetValues(typeof(TEnum)).OfType<T>();

编辑:我建议删除projection参数,并像这样简单地定义您的方法:

public static IEnumerable<TEnum> AsEnumerable<TEnum>() where TEnum : struct
{
    if (!typeof(TEnum).IsEnum)
        throw new InvalidOperationException("Type parameter TEnum must be an enum");
    return Enum.GetValues(typeof(TEnum)).OfType<TEnum>();
}

如果确实需要执行投影,则可以对返回的序列使用标准 LINQ Select 操作:

var optionsA = AsEnumerable<RegexOptions>();
var optionsB = AsEnumerable<RegexOptions>().Select(o => o.ToString());

这将为您提供与代码几乎相同的简洁性,但省去了维护可选参数的麻烦。

编辑2:如果你真的想为投影定义一个重载,我建议实现其中的所有逻辑,然后使用无参数版本中的标识函数调用它:

public static IEnumerable<TEnum> AsEnumerable<TEnum>() where TEnum : struct
{
    return AsEnumerable<TEnum, TEnum>(e => e);
}
public static IEnumerable<TResult> AsEnumerable<TEnum, TResult>(
    Func<TEnum, TResult> projection) where TEnum : struct
{
    if (!typeof(TEnum).IsEnum)
        throw new InvalidOperationException("Type parameter TEnum must be an enum");
    return Enum.GetValues(typeof(TEnum)).OfType<TEnum>().Select(projection);
}

示例调用:

var optionsA = AsEnumerable<RegexOptions>();
var optionsB = AsEnumerable<RegexOptions, string>(o => o.ToString());

相关内容

  • 没有找到相关文章

最新更新