为什么不能投射一个实例:
while
...到这个界面:
sealed class Foo
{
public void Go() { }
}
...即使interface IBar
{
void Go();
}
的签名为Foo
?
如何将IBar
的实例转换为Foo
?假设我无法控制IBar
。
答案 0 :(得分:25)
不,C#不支持鸭子打字。
此问题的OOP方法是使用the Adapter Pattern。
你会这样做:
applicationContext.xml
每当你有一个class FooBarAdapter : IBar {
private readonly Foo foo;
public FooBarAdapter(Foo foo) {
this.foo = foo;
}
public void Go() {
this.foo.Go();
}
}
但需要一个Foo
时,你可以按需包装它:
IBar
我注意到,如果public void ContrivedScenario() {
Foo foo = GetFooFromExternalDependency();
FooBarAdapter adapter = new FooBarAdapter( foo );
this.NeedsIBar( adapter );
}
public void NeedsIBar(IBar bar) { ... }
- 到 - Foo
转换发生很多,您可以使用隐式转换,因此您不需要显式构造IBar
个实例,但是如果这是一个很好的软件工程实践,那么这是值得商榷的:
FooBarAdapter
这样你可以这样做:
class FooBarAdapter : IBar {
// (same as above)
public static implicit operator FooBarAdapter(Foo foo) {
return new FooBarAdapter( foo );
}
}
C#不支持duck-typing的一个原因是因为类的接口(在OOP意义上,不是文字public void ContrivedScenario() {
Foo foo = GetFooFromExternalDependency();
this.NeedsIBar( foo ); // the conversion from `Foo foo` to `FooBarAdapter` happens implicitly
}
)与另一个共享相同的标识符,并不意味着它们是兼容。例如interface
(杀死进程)和Process.Kill
(杀死所有人类)可能不应该互换使用......除非你真的想要。
答案 1 :(得分:3)
C#没有“鸭子打字”。为了将实例从一种类型转换为另一种类型,它们必须具有继承关系或定义了自定义转换过载。在这种情况下,如果Foo没有被密封,你可以为Foo创建一个简单的子类:
class SubFoo : Foo, IBar {
void Go()
{
base.Go();
}
}
但是由于Foo本身是密封的,这是不可能的,所以你必须使用像这样的包容。
class ContainsFoo : IBar
{
ContainsFoo(Foo foo)
{
this.foo = foo;
}
void Go()
{
this.foo.Go();
}
}
答案 2 :(得分:3)
除了@Dai's answer之外,如果你想在测试项目中进行foo-bar演员,可以选择使用a mock framework。
var bar = Mock.Of<IBar>();
Mock.Get(bar).Setup(b => b.Go()).Callback(() => foo.Go());
MethodThatNeedsIBar(bar);
框架创建IBar
到foo
类型的代理,就像适配器一样工作,但它更容易设置,代码更少。
答案 3 :(得分:1)
还有Impromptu-Interface包来处理包裹的鸭子打字。它是一个完善的框架,有多种选择,包括处理集合的能力。