使用多个类/接口列出过滤

时间:2011-11-23 23:25:55

标签: c# generics interface

基本上我有一个对象列表,其中每个对象可能实现一组不同的接口:

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();
}

5 个答案:

答案 0 :(得分: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(); 
}

答案 1 :(得分: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 { }

使用上面定义的 Class

填充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();
} 

答案 2 :(得分:2)

不可能完全按照自己的意愿行事。

这是你可以做的。

首先,您只想对实施IXIYIZ的类型进行操作?然后将您的.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.
}

答案 3 :(得分: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和&amp;,那么你只想执行循环。 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();
}

我希望这会有所帮助。

答案 4 :(得分:0)

在DoStuff中。你能做到吗

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

...并为其他接口执行此操作。