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ため、Tより一般的ですTEnum。inIEnumerable<out T> Tは共変ですが、なぜエラーが発生するのですか?

4

1 に答える 1

3

共分散は、2 つの型の間にポリモーフィックな関係がある場合にのみ適用されます。あなたの場合、関連するように制約され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>();
}

射影を実行する必要がある場合はSelect、返されたシーケンスに対して標準の LINQ 操作を使用できます。

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

これにより、コードと実質的に同じ簡潔さが得られますが、オプションのパラメーターを維持する手間が省けます。

編集2 : プロジェクションのオーバーロードを本当に定義したい場合は、その中にすべてのロジックを実装してから、パラメーターなしのバージョンの ID 関数を使用して呼び出すことをお勧めします。

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 に答える