声明一个接口,其中具体实现具有具体类型

The*_*dge 1 c# design-patterns

public interface ISomeInterface
{
    IOut SomeMethod(IIn aIn)
}

public class MyOut : IOut
{
    public string AnExtraProp {get; set;}
}

public class MyIn : IIn
{
    public string AnotherExtraProp {get; set;}    }
}

public class MyConcreteOfSomeInterface : ISomeInterface
{
     public MyOut SomeMethod(MyIn aIn)
     {
     }
} 
Run Code Online (Sandbox Code Playgroud)

是否可以让许多类(例如 MyConcreteOfSomeInterface、MyConcrete2OfSomeInterface,...)实现一个接口(例如 ISomeInterface),但仍具有具体类型的参数(例如 MyIn、MyOut 等)。

我意识到我可以声明:

public interface ISomeInterface<TIn, TOut>
{
    TOut SomeMethod(TIn aIn)
}
Run Code Online (Sandbox Code Playgroud)

但由于 ISomeInterface 有很多方法,所以这是不切实际的。假设我需要添加其他方法 SomeMethod2 和 SomeMethod3 那么我最终会得到:

public interface ISomeInterface<TIn, TOut, TIn2, TOut2, TIn3, TOut3>
{
    TOut SomeMethod(TIn aIn)
    TOut2 SomeMethod(TIn2 aIn)
    TOut3 SomeMethod(TIn3 aIn)
}
Run Code Online (Sandbox Code Playgroud)

所以声明很快就变得难以处理。

我可以使用什么设计模式来实现:

  1. 许多实现接口 ISomeInterface AND 的具体类
  2. 使用实现必要接口 IIn、IOut 的具体参数/返回值?

ISomeInteface 上有许多方法,具有不同类型的参数/接口组合。

Eri*_*ert 5

让我们简化问题。假设我们有:

class Animal {}
class Giraffe : Animal {}
interface IFoo 
{
  Animal M(); 
}
Run Code Online (Sandbox Code Playgroud)

那么我们可以有

class C : IFoo
{
  public Giraffe M() => new Giraffe();
}
Run Code Online (Sandbox Code Playgroud)

很不幸的是,不行。接口实现必须完全匹配。

现在,您可能会想“嘿,界面要求返回一个动物,而我要返回一个动物,即长颈鹿,那么有什么问题呢?”

答案是没有问题。C# 可以有一个可以实现此功能的类型系统,并且此功能已被多次提出。它被称为“返回类型协方差”,如果您在这里进行搜索,您会发现很多关于它的问题。

然而 C# 没有这个功能,所以你运气不好。你能做的最好的事情是:

class C : IFoo 
{
  Animal IFoo.M() => this.M();
  public Giraffe M() => new Giraffe();
}
Run Code Online (Sandbox Code Playgroud)

现在你很好了。该IFoo契约是显式实现的,并且类的公共表面具有更具体的签名。

同样,如果我们有:

interface IBar() 
{
  void N(Giraffe g); 
}
Run Code Online (Sandbox Code Playgroud)

这是不合法的:

class D : IBar
{
  public void N(Animal g) { ... }
}
Run Code Online (Sandbox Code Playgroud)

再说一遍,这是完全明智的。IBar 要求 DN 是您可以将长颈鹿传递给的物体,而 DN 是您可以将长颈鹿或任何动物传递给的物体。但同样,C# 不支持此功能。这称为形式参数逆变,只有极少数编程语言支持它。

搜索 C# 协方差和逆变,了解 C# 支持哪些类型的方差的详细信息

另请注意,这不是类型安全的:

interface IBaz 
{
  void P(Animal a);
}
class E : IBaz
{
  public void P(Giraffe g) { } 
}
Run Code Online (Sandbox Code Playgroud)

因为你需要能够说((IBaz)(new E())).P(new Tiger())IBaz说实现必须能够接受任何动物,因此您不能使用仅接受长颈鹿的方法来实现它。从逻辑上讲,返回类型变得更具体是安全的,但形式参数类型必须变得不那么具体。这就是为什么它是返回类型方差而形式参数类型方差的原因,因为可转换性的方向在相反情况下发生变化。