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

Генерация кодов выражений С# и F #

Посмотрите на код, сгенерированный F # для простой функции:

let map_add valueToAdd xs =
    xs |> Seq.map (fun x -> x + valueToAdd)

Сгенерированный код для лямбда-выражения (экземпляр функционального значения F #) будет выглядеть так:

[Serializable]
internal class [email protected] : FSharpFunc<int, int> {
    public int valueToAdd;
    internal [email protected](int valueToAdd) { this.valueToAdd = valueToAdd; }
    public override int Invoke(int x)  { return (x + this.valueToAdd); }
}

И посмотрите почти на тот же код С#:

using System.Collections.Generic;
using System.Linq;

static class Program {
    static IEnumerable<int> SelectAdd(IEnumerable<int> source, int valueToAdd) {
        return source.Select(x => x + valueToAdd);
    }
}

И сгенерированный код для выражения лямбда С#:

[CompilerGenerated]
private sealed class <>c__DisplayClass1 {
    public int valueToAdd;
    public int <SelectAdd>b__0(int x) { return (x + this.valueToAdd); }
}

Итак, у меня есть несколько вопросов:

  • Почему F # -генерированный класс не помечен как sealed?
  • Почему F # -генерированный класс содержит общедоступные поля, поскольку F # не разрешает изменчивые закрытия?
  • Почему класс, сгенерированный F #, имеет конструктор? Он может быть полностью инициализирован публичными полями...
  • Почему С# -генерированный класс не помечен как [Serializable]? Также классы, сгенерированные для выражений последовательности F #, также стали [Serializable], а классы для итераторов С# этого не делают.
4b9b3361

Ответ 1

Поскольку они сгенерированы с помощью компилятора, проблемы с закрытыми/открытыми полями являются немного спорными - вы не должны их видеть, кроме как с помощью инструментов отладки - как бы вы их подклассифицировали или мутировали, за исключением того, что шагали по компилятору? Если у вас есть такой уровень отладочного доступа, вы можете все равно его мутировать (через отражение).

Для С# ему нужно, чтобы top было полем, позволяющим использовать определенное использование ref/out, и разрешать правильное использование с захваченными изменчивыми структурами (да, зло, мы знаем). Я предполагаю, что F # здесь похожа (можете ли вы мутировать суб- [sub- []] член захваченного значения?). Возможно, члены могли быть внутренними.

Re [Serialziable]; почему то, что лежит в основе закрытия, может быть сериализуемым? Делегаты делают крайне бедных кандидатов на сериализацию. Возможно, характер F # означает, что он лучше подходит для продолжения операции (в середине потока) на диск, но в целом я бы не рекомендовал его. Я бы не ожидал, что эти объекты (итераторы и классы захвата) будут сериализованы.

Ответ 2

Почему F # -генерированный класс не помечен как запечатанный?

Потому что компилятор не делает (это, в конце концов, выбор кода.

Почему класс, порожденный F #, содержит публичные поля, поскольку F # не разрешает изменчивые закрытия?

Вам нужно будет получить ссылку на экземпляр, чтобы изменить его. Но вы не можете, поэтому быть изменяемым не имеет значения. И, вероятно, это избегает необходимости в специальном случае, когда mutable захватывается в закрытии.

Почему класс, сгенерированный F #, имеет конструктор? Он может быть полностью инициализирован публичными полями...

Опция выбора кода снова.

Почему С# -генерированный класс не помечен как [Serializable]? Также классы, сгенерированные для выражений последовательности F #, также стали [Serializable], а классы для итераторов С# этого не делают.

Дополнительные варианты генерации кода.

Ни один из этих вариантов не является видимым разработчиком (т.е. не имеет никакого отношения к клиентскому коду), это действительно не имеет значения.