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)
所以声明很快就变得难以处理。
我可以使用什么设计模式来实现:
ISomeInteface 上有许多方法,具有不同类型的参数/接口组合。
让我们简化问题。假设我们有:
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说实现必须能够接受任何动物,因此您不能使用仅接受长颈鹿的方法来实现它。从逻辑上讲,返回类型变得更具体是安全的,但形式参数类型必须变得不那么具体。这就是为什么它是返回类型协方差而形式参数类型反方差的原因,因为可转换性的方向在相反情况下发生变化。