C# 使用接口与Func或操作

C# 使用接口与Func或操作,c#,.net,C#,.net,我已经写了10年的C#代码,但我在确切地知道什么时候使用接口和使用Func或Action方面非常薄弱。在我看来,在许多调用接口上的方法的地方,Func或Action也可以工作。所以,我想我的问题是。如果我的接口只有一个方法,或者可能有几个方法,那么使用Func或Action是否有任何缺点?对我来说,使用Func或Action似乎更干净 非常感谢。如果预期实现非常短(一行或两行),尤其是如果预期实现需要局部变量(闭包),则应使用委托和lambda表达式。如果您不真正关心正在使用的对象类型,则应使用

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


非常感谢。

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

如果您不真正关心正在使用的对象类型,则应使用接口

让我们以教科书为例

公营动物

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

我想您可以将
Action
Func
与包含一个方法的接口进行比较,区别在于您可以提供满足参数/返回值要求的任何
Action
Func
,其中使用接口时,提供的对象必须实现该接口

也许您可以调用
Action
Func
“匿名单方法接口”


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

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

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

Jon Skeet有使用Func和Action的能力

接口允许您执行以下操作:

IAnimal animal = AnimalFactory.GetAnimal();
animal.Run();
使用上面的代码,你不知道或不关心它是什么样的动物。你只知道它可以运行,你想让它运行更重要的是,来电者不知道动物如何奔跑。这就是动作和接口/多态性之间的区别。做某事的逻辑在具体的类中

当调用方知道实际逻辑时,操作将允许您对每个实例执行相同的操作,而不是让每个具体实例执行以下操作:

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

上述代码行是只由调用方决定应该发生什么的操作,而不是通过简单地调用实际实例上的方法将逻辑委派给它


它们解决不同的问题,所以我很好奇人们如何认为它们在某些情况下是可以互换的。

也许你可以用一个简单的例子更清楚地回答你的问题,你可以问这两个问题中哪一个应该使用。我想我介绍了你什么时候可以最好地使用它们。它们就像一个由不同类组成的容器,所有这些类都共享一些共同的功能(使用不同的实现)@deepee1-我认为问题已经足够清楚了。如果我用代码把问题弄得乱七八糟,人们可能会对整件事大惊小怪。可能是重复的我猜你选错了书。问题被标记为
C
:)。。。。是的,我注意到了。另一方面,我将直接从java编程书中了解java和c#接口之间的区别:)最后一段代码很糟糕。您不需要根据对象的类型进行if/switch操作。在这种情况下,您只需按照“moveQuick()”的思路调用一个方法,然后如果动物可以运行,它就可以在内部调用run(),否则它可以默认为move()。@Shark接口在C#中的作用与在java中的相同。委托可以作为接口应用程序的子集,这就是“命令模式”。任何可以用委托实现的东西都可以用接口模型来实现,接口模型只需要更多的代码就可以实现。代理是一种方便的机制,你永远不需要它们,它们只是让事情变得更容易。就像属性和许多getter和setter一样,它们只需要较少的代码就可以完成,但这并不意味着属性将替换所有方法。简短的实现并不真正适用于func和Actions,对吗?@RandyMinder:你是什么意思?对不起。我指的是您关于代理中代码行数的评论。我假设Func中的代码行数并不重要?@RandyMinder:正确;没关系。但是,如果超过一行或两行,调用代码看起来会很难看。Action/Func方式类似于Go中的接口处理方式。它使两个模块能够有效地无公共依赖关系(参数类型除外)。并不是说我会在任何情况下都推荐Action/Func。谢谢。至少在某些情况下,通过将实现封装在Func而不是接口方法中,不能同样有效地处理不同的实现吗?然后,不再调用接口方法,而是执行Func。谁是信息专家、调用者还是多态具体实例?如果接口的每个具体实例都有自己的逻辑,func将无法工作,因为它是在具体实例之外定义的。如果调用方知道逻辑,当然,func可以工作。您所展示的是一个具有多个方法的接口示例。如果
IAnimal
除了
public void Run()
之外什么都没有,那么它实际上没有任何好处。它不返回任何内容,如果
Run
有副作用
animals.ForEach(x => /* do something completely different here */);