2013-02-14 53 views
14

我的類實現了兩次IEnumerable<T>我怎樣才能得到LINQ工作,而不是每次鑄造hashtable當執行IEnumerable時,LINQ會感到困惑<T>兩次


我寫我自己的協變散列表實施方案也從.NET的IDictionary<TKey, TValue>繼承。最終,它實現了IEnumerable<T>兩次不同類型的T。我隱式地實現了主要的可枚舉接口,另一個明確地實現了。事情是這樣的(僞):

class HashTable<TKey, TValue> : 
    ... 
    IEnumerable<out IAssociation<out TKey, out TValue>>, 
    IEnumerable<out KeyValuePair<TKey, TValue>> 
{ 
    // Primary: 
    public IEnumerator<IAssociation<TKey, TValue>> GetEnumerator(); 
    // Secondary: 
    IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator(); 
} 

當我foreach哈希表,它需要as expected主枚舉:

using System; 
using System.Collections.Generic; 
using System.Linq; 

var hashtable = new HashTable<string, int>(); 
foreach (var kv in hashtable) 
{ 
    // kv is IAssociation<string, int> 
} 

現在我想要它做的LINQ同樣的事情,但它甩編譯器錯誤在我,因爲它不知道挑的擴展方法哪個接口:

var xs1 = from x in hashtable   // <-- 1 
      select x; 

var xs2 = hashtable.Select(x => x); // <-- 2 

錯誤1:找不到源類型'HashTable'的查詢模式的實現。 '選擇'未找到。考慮明確指定範圍變量'x'的類型。

錯誤2:'HashTable'沒有包含'Select'的定義,也沒有找到接受類型'HashTable'的第一個參數的擴展方法'Select'(你缺少using指令還是程序集引用? )

也許有一些接口或繼承技巧我不知道?


對於那些誰問,這裏是接口的全樹:

using SCG = System.Collections.Generic; 

public class HashTable<TKey, TValue> 
    : IKeyedCollection<TKey, TValue>, SCG.IDictionary<TKey, TValue> 

public interface IKeyedCollection<out TKey, out TValue> 
    : ICollection<IAssociation<TKey, TValue>> 

public interface ICollection<out T> : SCG.IEnumerable<T> 

public interface IAssociation<out TKey, out TValue> 

// .NET Framework: 
public interface IDictionary<TKey, TValue> 
    : ICollection<KeyValuePair<TKey, TValue>> 

public interface ICollection<T> 
    : IEnumerable<T> 

現在你可以看到,爲什麼我不能讓KeyValuePair<TKey, TValue>IAssociation<TKey, TValue>相同。

+4

您是否嘗試過手動指定'Select'的[generic arguments](http://msdn.microsoft.com/zh-CN/library/bb548891.aspx)?聽起來像是無法推斷它們。特別是,你需要手動指定'TSource',但是一旦你做了一個,你就需要做我想的。不幸的是,這會阻止你返回匿名類型而沒有一些煩人的解決方法。 – 2013-02-14 15:39:29

+0

您可以包含'HashTable '的繼承/接口的其餘部分嗎? – 2013-02-14 15:40:01

+1

那麼它告訴你該怎麼做,至少在第一個錯誤。您必須明確說明'x'是什麼類型:from IAssociation x in hashtable select x; – Stonehead 2013-02-14 15:41:04

回答

24

當涉及到使用表達式作爲方法調用的參數時,編譯器沒有「主要」和「次要」接口實現的概念是很重要的。就類型而言,您的類型同樣適用於IEnumerable<IAssociation<...>>IEnumerable<KeyValuePair<...>>。這就是編譯器需要更多信息的原因。

最簡單的方法(IMO)將推出兩個新的屬性:

public IEnumerable<IAssociation<TKey, TValue>> Associations { get { return this; } } 
public IEnumerable<KeyValuePair<TKey, TValue>> KeyValuePairs { get { return this; } } 

這意味着你真的可以很容易地具體:

var query = from x in table.Associations 
      ...; 

var query = from x in table.KeyValuePairs 
      ...; 

不這隻能幫助編譯器保持高興 - 它也會幫助任何想要閱讀代碼的人。如果你發現你使用其中一個比其他更多,你總是可以讓HashTable只實現一個IEumerable<>並鍵入並保留其他屬性。

+0

我很喜歡這個答案。 – 2013-02-14 15:43:14

+0

是否沒有其他方式通過直接實現它們來滿足您的編譯器? – antonijn 2013-02-14 15:49:35

+1

@Antonijn:是的,您可以通過明確指定類型參數來滿足編譯器的要求...... – 2013-02-14 15:57:37