2011-11-23 15 views
5

基本上我有每個對象有可能實現一組不同的接口的對象列表過濾:列表使用多類/接口

List<BaseObject> objects; 

class BaseObject 
{ 
    public void DoStuff(); 
} 

interface IX 
{ 
    void DoX(); 
} 

interface IY 
{ 
    void DoY(); 
} 

interface IZ 
{ 
    void DoZ(); 
} 

,我想寫點東西像這樣:

foreach(var obj in objects.OfType<BaseObject and IX>) 
{ 
    obj.DoStuff(); 
    obj.DoX(); 
} 

(例如我爲BaseObject和IX類型的對象執行特定算法,而不必在那裏進行類型轉換)

是否可以在C#中執行? 什麼是最優雅的解決方案?

我可以這樣做:

foreach(var obj in objects.OfType<IX>) 
{ 
    var baseobj = (BaseObject)obj.DoStuff(); 
    obj.DoX(); 
} 

,但我覺得它難看。

而且我可能需要將特定操作應用於實現說接口IX和接口IZ的類型。

foreach(var obj in objects.OfType<BaseType and IX and IZ>) 
{ 
    obj.DoStuff(); 
    obj.DoX(); 
    obj.DoZ(); 
} 

回答

4

一種可能的方式是使用dynamic

foreach(var xz in objects.Where(o => o is IX && o is IZ).Select(o => (dynamic)o)) 
{ 
    xz.DoStuff(); 
    xz.DoX(); 
    xz.DoZ(); 
} 

當然,你仍然可以投,如果你不希望使用dynamic

foreach(var xz in objects.Where(o => o is IX && o is IZ)) 
{ 
    xz.DoStuff(); 
    ((IX)xz).DoX(); 
    ((IZ)xz).DoZ(); 
} 
+0

我想我會失去intellisense,但它看起來很酷! – JBeurer

+0

@JBeurer,是的,這是一個折衷:) –

2

有了這些類和接口...

List<BaseObject> objects; 

class BaseObject 
{ 
    public void DoStuff(); 
} 

interface IX 
{ 
    public void DoX(); 
} 

interface IY 
{ 
    public void DoY(); 
} 

interface IZ 
{ 
    public void DoZ(); 
} 

class X : BaseObject, IX { } 
class Y : BaseOjbect, IY { } 
class Z : BaseObject, IZ { } 
class XY : BaseObject, IX, IY { } 

Asumming您填充ojbect以上

foreach (var o in objects) 
{ 
    o.DoStuff(); 
    if (o is IX) 
    ((IX)o).DoX(); //executed on class X and XY 
    if (o is IY) 
    ((IY)o).DoY(); //excuted on class Y and XY 
    if (o is IZ) 
    ((IZ)o).DoZ(); //excuted on class Z 
} 

定義的任何類應該做你在找什麼。

已更新您的評論。

foreach (var o in objects) 
{ 
    o.DoStuff(); 
    if (o is IX and o is IY) 
    { 
    // do something different only for XY 
    } 
    else if (o is IX) 
    ((IX)o).DoX(); //executed on class X 
    else if (o is IY) 
    ((IY)o).DoY(); //excuted on class Y 
    else if (o is IZ) 
    ((IZ)o).DoZ(); //excuted on class Z 
} 

修訂沒有類型轉換。

需要另一個接口。 (另外,DoStuff()應該在所有IX,IY,IZ上)。

interface IXY : IX, IY { } 

//  This IXY could be var, but just strongly typing it for example 
foreach (IXY o in objects.OfType(IXY) 
         .Cast<IXY>()) 
{ 
    o.DoStuff(); 
    o.DoX(); 
    o.DoY(); 
} 

你也可以做些事情CRAZY像:

foreach (var obj in objects.OfType<IX>() 
          .OfType<IY>() 
          .OfType<IZ>() 
          .Select(o => new 
            { 
             AsIX = (IX)o, 
             AsIY = (IY)o, 
             AsIZ = (IZ)o 
            }) 
{ 
    obj.AsIX.DoX(); 
    obj.AsIY.DoY(); 
    obj.AsIZ.DoZ(); 
} 
+0

不是真的,我想執行一個只針對實現了X和Y接口的對象。 – JBeurer

+0

更新之後,你說的很對,但是你的解決方案不幸的是涉及到很多類型轉換,這正是我想要回避的:( – JBeurer

+0

我已經根據你的提交更新了,你爲什麼要求每個變量都是在循環內部進行類型轉換,似乎不必要地複雜(但可能)。 –

0

在DoStuff。你能做

if (this is IX) { (this as IX).DoX(); } 

...併爲其他接口做到這一點。

2

這是不可能做到你想要的。

以下是您可以做的事情。

首先,您只希望對類型執行IX,IYIZ?然後將您的.OfType方法鏈接在一起。OfType將過濾列表中爲您提供:

foreach (var obj in objects.OfType<IX>().OfType<IY>().OfType<IZ>()) { 

不幸的是,obj只會強類型IZ,因爲有作爲實現所有3個接口類型沒有這樣的事情。所以,你還是要投,但是你保證,中投將工作:

foreach (var obj in objects.OfType<IX>().OfType<IY>().OfType<IZ>()) { 
    ((IX)obj).DoX(); 
    ((IY)obj).DoY(); 
    ((IZ)obj).DoZ(); // Note, You could also just do obj.DoZ(), but consistency looks better. 
} 
+0

是的,這是它如何寫入ATM – JBeurer

+0

那麼,這是一樣好因爲它得到:-) –

2

用最簡潔的方式,以避免大量的鑄造和類型的測試是介紹會爲您整理的擴展方法。

試試這個:

public static void DoAs<T>(this object @this, Action<T> action) 
    where T : class 
{ 
    var t = @this as T; 
    if (t != null) 
    { 
     var a = action; 
     if (a != null) 
     { 
      a(t); 
     } 
    } 
} 

現在,我在你的最後一個例子循環,你只是想,如果對象實現兩個IX & IZ執行循環的假設。所以,你會接着寫:

foreach(var obj in objects) 
{ 
    obj.DoAs<IX>(x => 
     x.DoAs<IZ>(z => 
     { 
      obj.DoStuff(); 
      x.DoX(); 
      z.DoZ(); 
     })); 
} 

你的第一個/環路中間不需要任何新的擴展方法,我認爲這應該是很簡單:

foreach(var obj in objects.OfType<IX>()) 
{ 
    (obj as BaseObject).DoStuff(); 
    obj.DoX(); 
} 

我希望這有助於。

+0

非常獨特的想法!到目前爲止,這種情況一直很接近。 – JBeurer