2010-12-22 62 views
0

我有兩個類,CheckboxItemsList其中擴展通用列表和CheckboxItems,其中包含類型CheckboxItem類型的對象的列表。使用從LINQ通用列表派生的類

我想使用LINQ能夠根據CheckboxItems對象的屬性過濾CheckboxItemsList。雖然返回類型總是一個通用列表,但我希望它是一個CheckboxItemsList。

所以我想基本的問題是,linq可以返回一個相同類型的列表,它以開始?由於我無法將基類轉換爲派生類,除了迭代linq查詢的結果並逐行重建派生列表對象之外,是否有其他選擇?這並不是說這是世界末日,但我對linq來說相對陌生,並且想知道是否有更好的方法來做到這一點。

我想要什麼:

CheckboxItemsList newList = MyCheckboxItemsList.Where(item=>item.Changed); 

(顯然是行不通的,因爲查詢將返回List<CheckboxItems>,不CheckboxItemsList

的對象,一般爲:

public class CheckboxItemsList: List<CheckboxItems> 
{ 
    // does not add any fields, just access methods 
} 

public class CheckboxItems : IEnumerable<CheckboxItem> 
{ 
    public long PrimaryKey=0; 
    protected CheckboxItem[] InnerList; 
    public bool Changed 
    { 
     get { 
      return (InnerList.Any(item => item.Changed)); 
     } 
    } 
    .... 
} 

回答

1

不,這是不可能的。您需要添加代碼才能執行此操作。

例如,您可以添加一個構造函數,像這樣:

public CheckboxItemsList(IEnumerable<CheckboxItems> checkboxItems) { 
    // something happens 
} 

那麼你可以說

CheckboxItemsList newList = new CheckboxItemsList(
    MyCheckboxItemsList.Where(item => item.Changed) 
); 

此外,您可以添加一個擴展方法,像這樣

static class IEnumerableCheckboxItemsExtensions { 
    public static ToCheckboxItemsList(
     this IEnumerable<CheckboxItems> checkboxItems 
    ) { 
     return new CheckboxItemsList(checkboxItems); 
    } 
} 

然後

CheckboxItemsList newList = 
    MyCheckboxItemsList.Where(item => item.Changed) 
         .ToCheckboxItemsList(); 
+0

好的,第一種選擇是我在想什麼。似乎奇怪的是,linq沒有內置的方式來返回一個接受它返回的對象的其他類型的列表,例如, `newlist = MyCheckboxItemsList.Where(item => item.Changed).ToList(typeof(CheckboxItemsList))` – 2010-12-22 16:06:56

+0

@jamietre:不,它並不奇怪。請記住,每項功能都需要設計,開發,測試和維護,並且與其相關的成本包括但不限於機會成本。 – jason 2010-12-22 16:22:29

0

沒有,有沒有內置的方法來做到這一點。你有兩個主要選擇:

  1. 添加一個構造函數,以您的CheckboxItemsList類,帶有一個IEnumerable<CheckboxItems>或相似。將該集合傳遞給需要IEnumerable<T>base List<T> constructor。然後,該基類的構造應該填充列表爲您提供:

    var newList = 
        new CheckboxItemsList(MyCheckboxItemsList.Where(item=>item.Changed)); 
    // ... 
    public class CheckboxItemsList : List<CheckboxItems> 
    { 
        public CheckboxItemsList(IEnumerable<CheckboxItems> collection) 
         : base(collection) 
        { 
        } 
    } 
    
  2. 創建需要一個IEnumerable<CheckboxItems>或類似的擴展方法,並返回一個填充CheckboxItemsList

    var newList = MyCheckboxItemsList.Where(item=>item.Changed) 
               .ToCheckboxItemsList(); 
    // ... 
    public static class EnumerableExtensions 
    { 
        public static CheckboxItemsList ToCheckboxItemsList(
         this IEnumerable<CheckboxItems> source) 
        { 
         var list = new CheckboxItemsList(); 
         foreach (T item in source) 
         { 
          list.Add(item); 
         } 
         return list; 
        } 
    } 
    

(當然,對於你可以實現這兩個選項的完整性,然後擴展方法將它的IEnumerable<CheckboxItems>參數傳遞給構造函數,而不是手動循環和添加每個項目。)

1

LINQ適用於IEnumerable<T>IQueryable<T>和結果類型所有LINQ操作(WhereSelect)等,將返回其中之一。標準ToList函數返回List<T>類型的具體名單,你可能需要拿出一個擴展方法,如:

public static CheckboxItemsList ToItemList(this IEnumerable<CheckboxItem> enumerable) 
{ 
    return new CheckboxItemsList(enumerable); 
} 
1

您還可以使用「轉換操作符」,如下圖所示:

public class CheckboxItemsList: List<CheckboxItems> 
{ 


     public static implicit operator CheckboxItems(IEnumerable<CheckboxItems> items)    
     { 
      var list = new CheckboxItemsList(); 
      foreach (var item in items) 
      { 
       list.Add(item); 
      } 
      return list; 
     } 
} 

現在,下面的代碼將工作。

CheckboxItemsList newList = MyCheckboxItemsList.Where(item=>item.Changed); 

從MSDN:

A轉換操作者聲明包括隱含的關鍵字引入一個用戶定義的隱式轉換。隱式轉換可能發生在各種情況下,包括函數成員調用,轉換表達式和賦值。這在第6.1節進一步描述。

包含顯式關鍵字的轉換運算符聲明引入了用戶定義的顯式轉換。顯式轉換可以在轉換表達式中發生,並在6.2節進一步描述。

0

這是我想出的,建立在別人的各種建議之上。一個通用的擴展方法:

public static T ToList<T>(this IEnumerable baseList) where T : IList,new() 
{ 
    T newList = new T(); 
    foreach (object obj in baseList) 
    { 
     newList.Add(obj); 
    } 
    return (newList); 
} 

所以,現在我可以做我想做:

CheckboxItemsList newList = MyCheckboxItemsList.Where(item=>item.Changed) 
    .ToList<CheckboxItemsList>(); 

另一個很明顯的解決發生在我身上,這也是有用的情況下派生列表類有字段屬性我需要維護在新列表中。

只需創建我的派生列表類的新實例,然後使用AddRange來填充它。

// When created with a CheckboxItemsList parameter, it creates a new empty 
// list but copies fields 
CheckboxItemsList newList = new CheckboxItemsList(OriginalList); 
newList.AddRange(OriginalList.Where(item => item.Changed));