2011-05-30 70 views
0

我有這種類型的列表IEnumerable<MyBaseType>我試圖創建一個額外的where子句來檢索列表中的特定項目。該特定值只存在於子類型MyFirstType和MySecondType上。不在MyBaseType上。使用子類型限制創建LINQ表達式

是否有可能來樣創造一個表達...

MyList.Where(b => (b is MyFirstType || (b is MySecondType)) && b.SpecificValue == message.SpecificValue); 

以上不工作因爲B型MyBaseType和SpecificValue不存在那裏。另請注意,我確實有另一個子類型MyThirdType,它們都沒有SpecificValue。

是什麼工作,做我想這是什麼?

foreach (dynamic u in MyList) 
{ 
    if (u is MyFirstType || u is MySecondType) 
    { 
     if (u.SpecificValue == message.SpecificValue) 
     { 
      //Extracted code goes here 
      break; 
     } 
    } 
} 

人有一個想法如何創建對於上述方案的LINQ表達?

回答

1

你的代碼到LINQ的直接翻譯where子句

string messageValue = "foo"; 
var result = baseList.Where(item => 
{ 
    dynamic c = item; 
    if(item is MyFirstType || item is MySecondType) 
    { 
     if(c.SpecificValue == messageValue) 
      return true; 
    } 
    return false; 
}); 

這將需要雖然使用動態測試類的類型 - 所以你還不如投項目要麼MyFirstType或直接使用MySecondType

另一種方法是使用反射來檢查屬性存在,使用這種方法,你不依賴於實際的類型的項目,只要他們有屬性,你感興趣的是:

string messageValue = "foo"; 
var result = baseList.Where(item => 
    { 
     var prop = item.GetType().GetProperty("SpecificValue"); 
     if (prop != null && prop.GetValue(item, null) == messageValue) 
      return true; 
     else return false; 
    }); 

如果修改類層次結構是一個選項,你可以有你MyFirstTypeMySecondType實現持有物業的接口,那麼你就可以在你的Linq查詢使用OfType()

interface ISpecific 
{ 
    string SpecificValue { get; set; } 
} 
class MyFirstType : MyBase, ISpecific 
{ 
    public string SpecificValue { get; set; } 
} 
... 
string messageValue = "foo"; 
var result = baseList.OfType<ISpecific>() 
        .Where(item => item.SpecificValue == messageValue); 
+0

我其實去動態的第一個版本。謝謝! – Per 2011-05-31 07:07:30

3

馬ybe有更好的解決方案,但就我看來,這可以工作得很好......如果你不介意表現。

那麼,通過聲明的接口開始:

public interface IMySpecialType 
{ 
    object SpecificValue {get; set;} //you didn't specify what type this is 
    //all your other relevant properties which first and second types have in common 
} 

然後,使MyFirstType和MySecondType從這個接口派生:

public class MyFirstType : MyBaseType, IMySpecialType 
{ 
    //snipet 
} 

public class MyFirstType : MySecondType, IMySpecialType 
{ 
    //snipet 
} 

然後,過濾器和投:

MyList 
    .Where(b => (b is MyFirstType) || (b is MySecondType)) 
    .Cast<IMySpecialType>() 
    .Where(b => b.SpecificValue == message.SpecificValue); 
    //do something 
0

更簡單的方法是創建一個界面來標記所有的類是物業具體價值。那麼這是一個孩子玩:

static void Main(string[] args) 
    { 
     List<MyBaseType> MyList = new List<MyBaseType>(); 
     ISpecificValue message = new MyFirstType(); 
     MyList.OfType<ISpecificValue>().Where(b => b.SpecificValue == message.SpecificValue); 
    } 
} 

class MyBaseType { } 
interface ISpecificValue { string SpecificValue { get; set; } } 
class MyFirstType : MyBaseType, ISpecificValue 
{ 
    public string SpecificValue; 
} 
class MySecondType : MyBaseType, ISpecificValue 
{ 
    public string SpecificValue; 
} 
+0

哎呀!我沒有注意到弗朗西斯的類似答案。我更喜歡我的,因爲內置的'OfType'對我來說似乎比這個'Where'和'Cast'奇怪的組合'MyFirstType'和'MySecondType'實現了硬編碼。 – Ssithra 2011-05-31 14:17:47

+0

注意到您的答案類似於弗朗西斯科。是的,它確實很簡單,但我不想再介紹另一個界面。 – Per 2011-06-01 04:41:52

+0

我非常尊重這個願望。不過,我會毫不猶豫地這樣做。這就是整個.Net框架的構想:儘可能抽象,接口而不是類......創建這種新的單行接口的成本可以忽略不計,接口的目的不難理解(感謝一個不言自明的名稱),並且它保證了代碼的可維護性。如果將來會出現具有** SpecificValue **屬性的其他類,則不必修改代碼以在「Where」子句測試中對此新類進行硬編碼。 – Ssithra 2011-06-01 08:01:14