在了解了 Go 如何处理接口并喜欢它之后,我开始思考如何在 C# 中实现类似的鸭子类型,例如this:
var mallard = new Mallard(); // doesn't implement IDuck but has the right methods
IDuck duck = DuckTyper.Adapt<Mallard,IDuck>(mallard);
DuckTyper.Adapt
方法将使用 System.Reflection.Emit
动态构建适配器。也许有人已经写过类似的东西了。我想这与模拟框架已经做的没有太大不同。
但是,如果 Mallard
实际上没有正确的 IDuck
方法,这会在运行时引发异常。为了在编译时尽早得到错误,我必须编写一个 MallardToDuckAdapter
这正是我想要避免的。
有更好的办法吗?
编辑:显然,我所说的“安全鸭子打字”的正确术语是结构性键入。
After looking at how Go handles interfaces and liking it, I started thinking about how you could achieve similar duck-typing in C# like this:
var mallard = new Mallard(); // doesn't implement IDuck but has the right methods
IDuck duck = DuckTyper.Adapt<Mallard,IDuck>(mallard);
The DuckTyper.Adapt
method would use System.Reflection.Emit
to build an adapter on the fly. Maybe somebody has already written something like this. I guess it's not too different from what mocking frameworks already do.
However, this would throw exceptions at run-time if Mallard
doesn't actually have the right IDuck
methods. To get the error earlier at compile time, I'd have to write a MallardToDuckAdapter
which is exactly what I'm trying to avoid.
Is there a better way?
edit: apparently the proper term for what I call "safe duck-typing" is structural typing.
发布评论
评论(4)
如果你面前没有一头活生生的、会呼吸的牛,你怎么能知道一头牛是否像鸭子一样行走,是否像鸭子一样嘎嘎叫呢?
鸭子类型是运行时使用的概念。编译时的类似概念是结构类型,据我所知不是由 CLR 支持。 (CLR 以主格类型为中心。)
确保鸭子类型在运行时不会抛出异常的常用方法是单元测试。
How can you know if a cow walks like a duck and quacks like a duck if you don't have a living, breathing cow in front of you?
Duck-typing is a concept used at run-time. A similar concept at compile-time is structural typing which is AFAIK not supported by the CLR. (The CLR is centred around nominative typing.)
The usual way to ensure that duck-typing throws no exception at run-time are unit-tests.
C# 的 DuckTyping
我不认为这个库会给你编译时错误的想法,我不确定这是否完全可行。使用单元测试来帮助弥补这一点。
DuckTyping for C#
I don't think this library will give you compile time errors thought, I am not sure that would be entirely feasible. Use Unit Tests to help compensate for that.
我认为没有其他方法会导致编译时错误。
然而,这正是单元测试的优势所在。您将编写一个单元测试来验证
映射是否成功。
I don't think there's another way in which you would get a compile time error.
However, this is something that Unit Testing is great for. You would write a unit test to verify that
successfully maps.
我知道 VB 10 计划使用隐式接口(这就是 Go 接口)(不知道 C#)。不幸的是,它们在发布之前就被废弃了(我认为它们甚至没有进入测试版......)。很高兴看到它们是否会出现在 .NET 的未来版本中。
当然,新的动态类型可用于实现大致相同的功能,但这仍然不一样——隐式接口仍然允许强类型,我认为这很重要。
I know that implicit interfaces (which is what Go interfaces are) were planned for VB 10 (no idea about C#). Unfortunately, they were scrapped before release (I think they didn’t even make it into beta …). It would be nice to see whether they will make an appearance in a future version of .NET.
Of course, the new
dynamic
types can be used to achieve much the same but this is still not the same – implicit interfaces still allow strong typing, which I find important.