19

在 Scala 中,我可以如下定义结构类型:

type Pressable = { def press(): Unit }

这意味着我可以定义一个函数或方法,它以可按下的东西作为参数,如下所示:

def foo(i: Pressable) { // etc.

我传递给该函数的对象必须为它定义了一个名为 press() 的方法,该方法与类型中定义的类型签名相匹配 - 不接受任何参数,返回 Unit(Scala 的 void 版本)。

我什至可以使用内联结构类型:

def foo(i: { def press(): Unit }) { // etc.

它基本上允许程序员拥有鸭子类型的所有好处,同时仍然具有编译时类型检查的好处。

C#有类似的东西吗?我在 Google 上搜索过,但找不到任何东西,但我对 C# 并不熟悉。如果没有,有没有计划添加这个?

4

4 回答 4

11

没有,也没有我知道的计划。仅命名(而不是结构)子类型(例如接口)。

(其他人可能也想看看

http://en.wikipedia.org/wiki/Nominative_type_system

http://en.wikipedia.org/wiki/Structural_type_system

)

(有些人可能会指出一些奇特的极端情况,例如foreach使用结构类型的语句 for GetEnumerator,但这是例外而不是规则。)

于 2010-05-14T00:44:47.913 回答
7

没有办法定义具有特定功能的结构类型。有一个为 C# 添加鸭子类型支持的库,可以在此处找到。

这是 Duck Typing 项目的示例。请注意,鸭子输入发生在运行时并且可能会失败。我的理解也是,这个库为鸭子类型的类型生成代理,这与 Scala 中所享有的优雅的编译时支持相去甚远。这很可能与这一代 C# 一样好。

public interface ICanAdd
{
    int Add(int x, int y);
}

// Note that MyAdder does NOT implement ICanAdd, 
// but it does define an Add method like the one in ICanAdd:
public class MyAdder
{
    public int Add(int x, int y)
    {
        return x + y;
    }
}

public class Program
{
    void Main()
    {
        MyAdder myAdder = new MyAdder();

        // Even though ICanAdd is not implemented by MyAdder, 
        // we can duck cast it because it implements all the members:
        ICanAdd adder = DuckTyping.Cast<ICanAdd>(myAdder);

        // Now we can call adder as you would any ICanAdd object.
        // Transparently, this call is being forwarded to myAdder.
        int sum = adder.Add(2, 2);
    }
}

这是使用良好的 ol 无聊接口实现相同目标的 C# 方式。

interface IPressable {
  void Press();
}

class Foo {
 void Bar(IPressable pressable) {
    pressable.Press();
 }
}

class Thingy : IPressable, IPushable, etc {
 public void Press() {
 }
}

static class Program {
 public static void Main() {
  pressable = new Thingy();
  new Foo().Bar(pressable);
 }
}
于 2010-05-14T00:48:48.527 回答
5

正如其他人所指出的,这在 .NET 中并不真正可用(因为这更多的是运行时问题而不是语言问题)。但是,.NET 4.0 支持导入的 COM 接口类似的东西,我相信这可以用于实现 .NET 的结构类型。请参阅此博客文章:

我自己还没有尝试过使用它,但我认为它可能使编译器作者能够为 .NET 编写具有结构类型的语言。(这个想法是您(或编译器)将在幕后定义一个接口,但它会起作用,因为由于 COM 等效功能,接口将被视为等效)。

此外,C# 4.0 支持dynamic关键字,我认为可以将其解释为结构类型(没有静态类型检查)。该关键字允许您在不知道(在编译时)对象是否具有所需方法的情况下调用任何对象的方法。这与 Igor 提到的“Duck typing”项目本质上是一样的(但这当然不是正确的结构类型)。

于 2010-05-14T00:54:31.897 回答
1

The awaitable pattern in C# can perhaps be interpreted as a limited, ad hoc instance of structural subtyping / existential typing. The compiler will only await objects that have access to a GetAwaiter() method that returns any INotifyCompletion object with a specific set of methods and properties. Since neither the 'awaitable' object nor the 'awaiter' object needs to implement any interface (except INotifyCompletion in the case of the latter), await is similar to a method that accepts structurally typed awaitable objects.

于 2016-01-01T20:54:22.673 回答