Skip to content

Instantly share code, notes, and snippets.

@controlflow
Last active January 1, 2016 01:28
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save controlflow/8072635 to your computer and use it in GitHub Desktop.
Save controlflow/8072635 to your computer and use it in GitHub Desktop.
Primary ctors
class ReverseForLookupItem : ForLookupItemBase
{
public ReverseForLookupItem([NotNull] PrefixExpressionContext context,
[NotNull] LiveTemplatesManager templatesManager,
[CanBeNull] string lengthPropertyName)
: base("forR", context, templatesManager, lengthPropertyName) { }
protected override IForStatement CreateStatement(CSharpElementFactory factory, ICSharpExpression expression)
{
...
}
}
// vs.
class ReverseForLookupItem([NotNull] PrefixExpressionContext context,
[NotNull] LiveTemplatesManager templatesManager,
[CanBeNull] string lengthPropertyName)
: ForLookupItemBase("forR", context, templatesManager, lengthPropertyName)
{
protected override IForStatement CreateStatement(CSharpElementFactory factory, ICSharpExpression expression)
{
...
}
}
@controlflow
Copy link
Author

Еще интересное и замечательное следствие использования primary-конструкторов - они вынуждают упрощать инициализацию, избегать сайдэффектов и виртуальных вызовов в конструкторе :)

@nesteruk
Copy link

К контексте convention over configuration можно будет договориться, что primary ctor - это в который что-то инжектится, тем самым не писать [InjectionConstructor] если их много.

@ViIvanov
Copy link

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

@controlflow
Copy link
Author

@nesteruk кажется невозможно будет отличить primary constructor от любого другого...

@Vilvanov я очень-очень сомневаюсь, что в C# когда-либо доберутся до ПМ, потому что это слишком масштабная фича чтобы уже запихнуть в насквозь мутабельный и императивный язык. Вроде уже говорили, что параметры класса (не знаю как они будут называться в спеке, по-моему логично называть именно параметрами класса как в F#) будут приватными полями (а если не говорили, то я готов поставить пиво что так будет), а значит никакого паттерн-матчинга. Добавлять в язык ПМ, который будет работать только по классам с primary-конструктором - это как-то ущербно, а во все остальное просто так ПМ не протащить. К тому же ПМ по сути "безопасен" только поверх неизменяемых структур данных (чтобы гарантировать отсутствие случаев типа match someType with SomeType(true) when someType.DoSideEffectAndChangeInternalValue() -> ... | SomeType(false) -> ... - казалось бы паттерн полный, но если мутировать структуру, то может не сработать ни один из кейсов).

@ViIvanov
Copy link

Хм, если параметры праймари-конструктора автоматом делаются полями, что смысл в этом вот:

public class Point(int x, int y) {
  public int X { get; } = x;
  // Зачем так, как выше - разве там не создастся ещё одно поле?
  public int Y { get; } = x % 2; // тут ещё одно поле не будет создано?

  // Почему не просто так, как ниже?
  // Понятно, что короче, но ради этого новый синтаксис воротить?
  public int X { get { return x; } }
}

хотя очень логично, конечно же.

А если всё и взаправду так, как ты говоришь, то тем более выбирать праймари ктор по методе "что читабельнее/компактнее/более ёмко" так же не верно. Раз праймари ктор определяет не просто синтаксис создания экземпляра, но и наполнение (список полей) то и выбираться должен не из эстетичеких понятий.

Ну, поживём-увидим :о))

@controlflow
Copy link
Author

Я не знаю точно, но скорее всего список полей будет определяться как в F# - если параметр класса использован только в вызове базового класса или инициализаторе поля/свойства (если такие будут в C# 6.0), то поле для него создаваться не будет.

class Point(int x, int y, int z) : PointBase(x) { // поля для x создано не будет
  public readonly int FieldY = y + 1; // поля для y тоже не будет создано

  // чтобы параметры классов были более полезными, логично ожидать что
  // в C# 6.0 появятся инициализаторы для автосвойств, аналогичные инициализаторам полей:
  public string MutableAutoPropertyZ { get; set; } = z.ToString(); // поля для z тоже не должно быть

  // про инициализаторы автосвойст не было информации,
  // но то что показали на NDC London об этом свидетельствует:
  public string ReadOnlyAutoPropertyZ { get; } = z; // поля для z по-прежнему не будет

  // это автосвойство без одного акцессора - без сеттера.
  // я сомневаюсь, что им можно будет присваивать в конструкторах
  // (как-то странно выглядело бы, сеттера нет, а присваивать можно),
  // но при этом их можно инициализировать как поле (нету никаких причин
  // не расширить эту фичу на обычные автосвойства). Будет полезно для коллекций:
  public List<string> Tags { get; } = new List<string>();
}

@controlflow
Copy link
Author

// и да, тут два readonly поля (которые явно написаны):
class Point(int x, int y) {
  public readonly int X = x;
  public readonly int Y = y;
}

// тут тоже два поля (readonly backing-поле автосвойства):
class Point(int x, int y) {
  public int X { get; } = x;
  public int Y { get; } = y;
}

// тут два backing-поля автосвойства (мутабельные):
class Point(int x, int y) {
  public int X { get; set; } = x;
  public int Y { get; set; } = y;
}

// тут два поля, получившиеся из параметров класса (скорее всего мутабельные):
class Point(int x, int y) {
  public int X { get { return x; } }
  public int Y { get { return y; } }
}

// абсолютно то же самое, только короче (показывали на NDC):
class Point(int x, int y) {
  public int X => x;
  public int Y => y;
}

// скорее всего можно будет так (два поля из параметров классов):
class Point(int x, int y) {
  public int X {
    get { return x; }
    set { x = value; }
  }

  public int Y {
    get { return y; }
    set { y = value; }
  }
}

@ViIvanov
Copy link

ViIvanov commented Jan 4, 2014

Кажется, слишком наворочено. Поживём-увидим :о)

@hazzik
Copy link

hazzik commented Apr 8, 2014

@controlflow

Так не работает

class Point(int x, int y) {
  public int X { get { return x; } }
  public int Y { get { return y; } }
}

(7,31): error CS9007: Parameters of a primary constructor can only be accessed in instance variable initializers and arguments to the base constructor.
(8,31): error CS9007: Parameters of a primary constructor can only be accessed in instance variable initializers and arguments to the base constructor.

Последние 3 примера не работают

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment