【问题标题】:Using Interfaces vs. Func or Action [closed]使用接口与 Func 或 Action [关闭]
【发布时间】:2012-10-31 14:05:44
【问题描述】:

我已经编写 C# 代码 10 年了,但我非常不知道何时使用接口与使用 Func 或 Action。在我看来,在调用接口上的方法的许多地方,Func 或 Action 也可以正常工作。所以,我想我的问题是这个。如果我的接口只有一个方法,或者可能有几个方法,那么使用 Func 或 Action 有什么缺点吗?使用 Func 或 Action 对我来说似乎更干净。

非常感谢。

【问题讨论】:

  • 也许你可以通过一个简单的例子更清楚地表达你的问题,以及你会质疑使用两者中的哪一个。
  • 我想我已经涵盖了您何时可以最好地使用它们。它们就像一个包含不同类的容器,它们都有一些共同的功能(具有不同的实现)
  • @deepee1 - 我认为这个问题已经很清楚了。如果我用代码把问题弄得乱七八糟,人们可能会倾向于对整个事情视而不见。

标签: c# .net


【解决方案1】:

我想您可以将ActionFunc 与包含一种方法的接口进行比较,不同之处在于您可以提供任何 ActionFunc 满足参数/返回值要求,在使用接口时,提供的对象必须实现该接口。

也许您可以调用ActionFunc“匿名单一方法接口”。

如果您从设计角度来看,您的类模型将是一个没有任何线条的块的绘图。

【讨论】:

  • Action/Func 方式类似于 Go 中接口的处理方式。它使两个模块有效地没有共同的依赖关系(参数类型除外)。并不是说我会在所有情况下都推荐 Action/Func。
【解决方案2】:

如果预计实现非常短(一两行),尤其是预计实现需要局部变量(闭包)时,您应该使用委托和 lambda 表达式。

【讨论】:

  • 简短的实现并不真正适用于 Funcs 和 Actions,对吗?
  • @RandyMinder:什么意思?
  • 对不起。我指的是您对委托中代码行数的评论。我假设 Func 中的代码行数并不重要?
  • @RandyMinder:正确;没关系。但是,如果超过一两行,调用代码会很丑。
【解决方案3】:

我不得不承认,我对这个问题有点困惑。和@deepee 一样,我同意这里的代码示例会很好地说明您为什么认为您会使用一种方法而不是另一种方法。

让我感到困惑的原因是,我没想过要问这个问题,因为它们有不同的用途。接口主要用于多态;这样人们就可以以相同的方式处理不同的实现。

Jon Skeet 有一个 good example 使用 Func 和 Action。

接口允许您这样做:

IAnimal animal = AnimalFactory.GetAnimal();
animal.Run();

使用上面的代码,你不知道也不关心它是什么动物。您只知道它可以运行并且您希望它运行。 更重要的是,调用者不知道动物是如何奔跑的。这就是 Action 和接口/多态性之间的区别。做某事的逻辑在具体类中。

一个动作将允许您为每个实例做同样的事情,当调用者知道实际逻辑时,而不是让每个具体实例做某事:

animals.ForEach(x => x.Run());

或者:

animals.ForEach(x => /* do something completely different here */);

上面的代码行是只有调用者决定应该发生什么的动作,而不是通过简单地调用一个方法将逻辑委托给实际实例

他们解决不同的问题,所以我很想知道人们如何认为他们在某些情况下可以互换。

【讨论】:

  • 谢谢。至少在某些情况下,通过将实现封装在 Func 中而不是接口方法中,不能同样有效地处理不同的实现吗?然后,不调用接口方法,而是执行 Func。
  • 谁是信息专家、调用者还是多态具体实例?如果接口的每个具体实例都有自己的逻辑,则 func 将不起作用,因为它是在具体实例外部定义的。如果调用者知道逻辑,那么 func 可以工作。
  • 您展示的是一个具有多种方法的接口示例。如果IAnimal 除了public void Run() 之外什么都没有,那它真的没有任何好处。它不会返回任何东西,如果Run 有副作用,它们是不可见的。 IAnimal 会很有用,因为它会导致通过其他方法可见的副作用,例如 PositionStamina。代表只会真正替换具有单一方法的接口。
  • +1 用于保持动物主题并将我留在代码中的内容表达出来:)
【解决方案4】:

当你并不真正关心你正在使用什么样的对象时,你会使用接口......

我们来看教科书的例子

公共类动物;

public class Dog : Animal, IRunningAnimal { }
public class Cheetah : Animal, IRunningAnimal { }
public class Fish : Animal, ISwimmingAnimal { }
public class Gator : Animal, ISwimmingAnimal, IRunningAnimal { }

public interface IRunningAnimal 
{
    public void Run();
}

public interface ISwimmingAnimal
{
    public void Swim();
}

public abstract class Animal
{
    /// ...
    public abstract void Move();
}

然后在代码中的某个地方...

RunningAnimal runner = getAnimal();
//make him run
runner.Run();

每只奔跑的动物可能以不同的方式奔跑,但它们都可以奔跑。

或更好

if(getAnimal() instanceof RunningAnimal) getAnimal().Run();
else getAnimal().Move();

【讨论】:

  • 我猜你选错书了。问题被标记为C# :)
  • .... 是的,刚刚注意到了。另一方面,我将学习 java 和 c# 接口之间的区别:)
  • 直接来自 Java 编程书籍? :)
  • 最后的 sn-p 代码太糟糕了。您永远不需要根据对象的类型来执行 if/switches。在这种情况下,您应该简单地按照“moveQuickly()”的方式调用一个方法,然后如果动物可以运行,它会在内部调用 run(),否则它可以默认为 move()。
  • @Shark 接口在 C# 中的作用与在 java 中的作用相同。委托可以看作是接口应用程序的一个子集,这就是“命令模式”。任何可以用委托实现的东西都可以用接口模型来实现,接口模型只需要更多的代码来完成它。委托是一种便利机制,您永远需要它们,它们只是让事情变得更容易。就像属性与许多 getter 和 setter 一样,它们只需更少的代码即可完成,但这并不意味着属性将取代所有 方法
猜你喜欢
  • 2013-10-26
  • 1970-01-01
  • 2012-07-28
  • 2011-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多