1

我写了这个 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. inIEnumerable<out T> T是不变的,那么为什么我仍然会收到错误消息?

4

1 回答 1

3

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

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

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

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

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());
于 2012-12-04T12:24:52.367 回答