2012-12-04 41 views
1

的IEnumerable的 我寫這EnumHelper方法 無法到位返回IEnumerable的<T>

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是convariant,所以爲什麼我仍然得到錯誤?

+1

協方差在這裏並不適用;編譯器如何知道'T'和'TEnum'之間的關係? (它不) –

+1

C#中值類型不支持協方差。 「where TEnum:struct」 –

+0

@Mark因爲T可以是任何東西,因爲我沒有約束,所以你應該能夠返回任何東西來代替T –

回答

3

協方差只適用於兩種類型之間存在多態關係的情況。在你的情況下,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()); 

這會給你幾乎與你的代碼一樣的簡潔性,但省卻了維護可選參數的麻煩。

編輯:如果你真的要定義一個超負荷的投影,我會建議其內部實現所有的邏輯,然後使用標識功能從參數的版本稱之爲:

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()); 
+0

@NasmiSabeer,然後你可以得到運行時錯誤。 –

+0

爲什麼我得到運行時錯誤? –

+0

@Douglas,謝謝你的回覆。這也是我的想法,但是我爲投影寫了一個超載 –

相關問題