Подтвердить что ты не робот

Имеет ли С# эквивалент структурной типизации Scala?

В Scala я могу определить структурные типы следующим образом:

type Pressable = { def press(): Unit }

Это означает, что я могу определить функцию или метод, который принимает в качестве аргумента что-то вроде Pressable, например:

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

Объект, который я передаю этой функции, должен определить для него метод с именем press(), который соответствует сигнатуре типа, определенной в типе, - не принимает аргументов, возвращает Unit (Scala версия void).

Я даже могу использовать структурный тип inline:

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

В основном это позволяет программисту получить все преимущества печати утинов, сохраняя при этом возможность проверки типа компиляции.

Есть ли у С# что-то подобное? Я Googled, но ничего не могу найти, но я не знаком с С# на любой глубине. Если нет, планируете ли вы добавить это?

4b9b3361

Ответ 1

Нет, и никаких планов, о которых я знаю. Только названный (а не структурный) подтипирование (например, интерфейсы).

(Другие могут также видеть

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

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

)

(Несколько человек могут указать некоторые экзотические угловые случаи, например, выражение foreach, используя структурную типизацию для GetEnumerator, но это exception, а не правило.)

Ответ 2

Не существует способа определить структурные типы, которые имеют определенную функцию. Существует библиотека, которая добавляет поддержку набора утинов для С#, которую можно найти здесь.

Это пример проекта Duck Typing. Обратите внимание, что утиная печать происходит во время выполнения и может выйти из строя. Я также понимаю, что эта библиотека генерирует прокси-серверы для типов, которые напечатаны утки, что далеко от элегантной поддержки времени компиляции, которой пользуются в Scala. Это, скорее всего, так же хорошо, как и с этим поколением С#.

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);
    }
}

Это способ С# для достижения той же самой цели с использованием полезных интерфейсов.

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);
 }
}

Ответ 3

Как отмечали другие, в .NET это действительно не так (поскольку это скорее вопрос времени исполнения, чем языка). Тем не менее,.NET 4.0 поддерживает аналогичную вещь для импортированных COM-интерфейсов, и я считаю, что это может быть использовано для реализации структурной типизации для .NET. Смотрите это сообщение в блоге:

Я еще не пытался играть с этим сам, но я думаю, что это может позволить авторам компилятора писать языки со структурной типизацией для .NET. (Идея состоит в том, что вы (или компилятор) определите интерфейс за сценой, но он будет работать, потому что интерфейсы будут рассматриваться как эквивалентные благодаря функции эквивалентности COM).

Кроме того, С# 4.0 поддерживает ключевое слово dynamic, которое, я думаю, может быть интерпретировано как структурное типирование (без проверки статического типа). Ключевое слово позволяет вам вызывать методы на любом объекте, не указав (во время компиляции), будет ли объект иметь требуемые методы. Это, по сути, то же самое, что и проект "Утка", упомянутый Игорем (но это, конечно, не правильная структурная типизация).

Ответ 4

Ожидаемый шаблон на С# можно интерпретировать как ограниченный, специальный экземпляр структурного подтипирования/экзистенциального ввода. Компилятор будет только await объектов, которые имеют доступ к методу GetAwaiter(), который возвращает любой объект INotifyCompletion с определенным набором методов и свойств. Поскольку ни "ожидаемый" объект, ни объект "awaiter" не должны реализовывать какой-либо интерфейс (кроме INotifyCompletion в случае последнего), await похож на метод, который принимает объекты с типичным типизированным ожиданием.