Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 测试对象以查看其是否实现了接口有什么错?_C#_Oop_Polymorphism - Fatal编程技术网

C# 测试对象以查看其是否实现了接口有什么错?

C# 测试对象以查看其是否实现了接口有什么错?,c#,oop,polymorphism,C#,Oop,Polymorphism,在它的评论中指出,“检查对象是否实现了接口,尽管它可能很猖獗,但这是一件坏事” 以下是我认为是这种做法的一个例子: public interface IFoo { void Bar(); } public void DoSomething(IEnumerable<object> things) { foreach(var o in things) { if(o is IFoo) ((IFoo)o).Bar(); } }

在它的评论中指出,“检查对象是否实现了接口,尽管它可能很猖獗,但这是一件坏事”

以下是我认为是这种做法的一个例子:

public interface IFoo
{
   void Bar();
}

public void DoSomething(IEnumerable<object> things)
{
   foreach(var o in things)
   {
       if(o is IFoo)
           ((IFoo)o).Bar();
   }
}
公共接口IFoo
{
空心钢筋();
}
公共无效剂量测定法(IEnumerable things)
{
foreach(事物中的var o)
{
if(o是IFoo)
((IFoo)o.Bar();
}
}
作为一个以前使用过这种模式变体的人,我的好奇心受到了激发,我寻找了一个好的例子或解释,解释为什么这是一件坏事,但却找不到


虽然我很可能误解了该评论,但有人能给我提供一个例子或链接来更好地解释该评论吗?

我希望该方法是这样的,它看起来更安全:

public void DoSomething(IEnumerable<IFoo> things)
{
   foreach(var o in things)
   {
           o.Bar();
   }
}
public void DoSomething(IEnumerable things)
{
foreach(事物中的var o)
{
o、 Bar();
}
}

要了解所提到的违反利斯科夫原则的行为:

这取决于你想做什么。有时可能是适当的-示例包括:

  • LINQ到对象,用于优化操作,如
    Count
    ,可通过专用成员在
    IList
    上更有效地执行
  • LINQ到XML,它用于提供一个非常友好的API,该API接受广泛的类型,并在适当的情况下迭代值
  • 如果要在Windows窗体中的特定控件下查找特定类型的所有控件,则需要检查每个控件是否为容器,以确定是否递归
在其他情况下,它不太合适,您应该考虑是否可以更改参数类型。这绝对是一种“气味”——通常情况下,你不应该关心交给你的任何东西的实现细节;您应该只使用声明的参数类型提供的API。这也被称为违反法律

不管周围武断的开发人员会说什么,有时候您只是想检查对象的执行时间类型。在不使用<代码>的情况下,正确地重写<代码>对象。(< /代码> /<代码>为< /代码> /<代码> GETYPE < /COD> >:它并不总是坏事,但它应该总是让您考虑是否有更好的方法。只有在真正最合适的设计下,才可谨慎使用


我个人更愿意像这样编写代码,请注意:

public void DoSomething(IEnumerable<object> things)
{
    foreach(var foo in things.OfType<IFoo>())
    {
        foo.Bar();
    }
}
public void DoSomething(IEnumerable things)
{
foreach(things.OfType()中的var foo)
{
foo.Bar();
}
}

它完成了同样的事情,但方式更简洁:)

原因是,如果不深入代码,该接口上的依赖项将不会立即可见。

如果您的方法要求您注入接口的实例,则无论实现如何,您都应该对其进行相同的处理。

在您的示例中,通常没有对象的通用列表,但是
ISomething
的列表和调用
ISomething.Bar()
将由具体类型实现,因此调用它的实现。如果这个实现什么都不做,那么你就不必做检查。

如果你想知道评论者为什么要发表评论,最好让他们解释一下

我不会认为你发布的代码是“坏”的。一个更“真实”的坏做法是使用接口作为标记。也就是说,您不打算实际使用接口的方法;相反,您已经在类上声明了接口,作为以某种方式描述它的一种方式使用属性而不是接口作为类上的标记。

标记接口在许多方面都是危险的。我曾经遇到过一个现实情况,一个重要的产品在marker界面的基础上做出了一个错误的决定,这里是:

也就是说,C#编译器本身在一种情况下使用“标记接口”。Mads在这里讲述了这个故事:

声明

检查对象是否实现了接口,然后重试 这可能是件坏事

在我看来,他过于教条了。正如其他人所回答的,您很可能能够将IFoo的集合传递给您的方法,并获得相同的结果

但是,接口对于向类添加可选功能非常有用。例如,.net framework提供了接口*。当实现此功能时,它向消费者指出,除了类的标准功能外,它还可以提供错误信息

在这种情况下,错误信息是可选的。WPF视图模型可能提供也可能不提供错误信息。如果不查询接口,如果没有具有巨大表面积的基类,就不可能实现此可选功能


*我们暂时忽略IDataErrorInfo接口糟糕的设计。

我不认为这是一件“坏事”,至少这本身不是。该代码只是“y-inz的xall”的文字转录,在需要这样做的情况下,它是完全可以接受的。为了简洁起见,您当然可以使用things.OfType()

反对它的主要原因是,根据OOP理论,接口旨在为对象可能替代的不同类型的“黑盒”建模。根据接口的实现来预测算法构成了将行为移动到该接口中的算法

本质上,接口是一种行为角色。如果您认为OOP是一个好主意,那么您应该只使用接口来建模行为,这样算法就不必这样做。我不认为这些天什么是OOP