ufcpp / UfcppSample

http://ufcpp.net/ 向けのサンプル
Apache License 2.0
136 stars 39 forks source link

Primary Constructors #441

Closed ufcpp closed 1 year ago

ufcpp commented 1 year ago

csharplang 2691

https://ufcpp.net/study/csharp/oo_construct.html に追記? 関連: https://ufcpp.net/study/csharp/datatype/record/

class C; は source generator で「属性1個だけつけて本体はコード生成する」シナリオで有用。 関連: https://ufcpp.net/study/csharp/misc/analyzer-generator/

ufcpp commented 1 year ago

「body 省略」に class C; 構文が採用されたことで、「file-scoped クラス定義」の望みは絶たれた。 ↑ file-scoped namespace みたいなのをクラスでもやりたいという話。 すでに record ではできる望みなかったので、それが正式に class/struct でも同様に。

ufcpp commented 1 year ago

空派生の類でも有用。

interface IA;
interface IB;
interface IC;

interface IAll : IA, IB, IC; // {} 書かない
ufcpp commented 1 year ago

初期化子とコンストラクターの実行順

class Base(int x) { }

class A(int x) : Base(x)
{
    public int X { get; } = x; // これ、 base(x) 呼びよりも前になる
}

class B : Base
{
    public int X { get; }

    public B(int x) : base(x)
    {
        X = x;
    }
}

そういやプライマリコンストラクターの有無関係なく、「派生側 初期化子 → 基底側 初期化子 → 基底側 ctor → 派生側 ctor」順だという話、うちのサイトにはまだ書いてない?

特に、「親クラスから virtual method 呼びたい」とかの時に「初期化子の方が先」仕様助かることが。

_ = new Derived("Hello");

class Base
{
    public Base() => Print(); // 何も表示されない。 Name が未初期化(null)。
    public virtual void Print() { }
}

class Derived : Base
{
    public string Name { get; }

    public Derived(string name) => Name = name;

    public override void Print() => Console.WriteLine(Name);
}
_ = new Derived("Hello");

class Base
{
    public Base() => Print(); // Name 初期化済み。
    public virtual void Print() { }
}

class Derived(string name) : Base
{
    public string Name { get; } = name;

    public override void Print() => Console.WriteLine(Name);
}
ufcpp commented 1 year ago

2重バッキングフィールド問題

https://github.com/ufcpp-live/UfcppLiveAgenda/issues/69#issuecomment-1475253019 https://github.com/ufcpp-live/UfcppLiveAgenda/issues/69#issuecomment-1475254939

あと、「Warn on shadowing by a member from base」

ufcpp commented 1 year ago

CS9109 Cannot use ref, out, or in primary constructor parameter 'x' inside an instance member

ref struct A([UnscopedRef] ref int x)
{
    [UnscopedRef]
    public ref int X => ref x; // ダメなんだ…
}

↓これOKなのに。

ref struct A(ref int x)
{
    ref int _x = ref x;

    public ref int X => ref _x;
}
ufcpp commented 1 year ago

method 指定でプライマリコンストラクターに属性つけれるように。

[method:A]
class C(int x);

class AAttribute : Attribute;

C# 12 の「普通のクラスにプライマリコンストラクター持てるようになった」と同時に作業してたけど、レコード型に対してもできるようになってるはず。

ufcpp commented 1 year ago
class C([field:A] int x) // これはダメ。「not valid」警告。x をキャプチャしてもそれはフィールド扱いではない。
{
    public int X => x;
}

class AAttribute : Attribute;

レコード型のは行ける。プロパティのバッキングフィールド。

ufcpp commented 1 year ago

既存記事、実行順の話

https://ufcpp.net/study/csharp/oo_construct.html

ちなみに、初期化子とコンストラクターの実行順序は、 変数初期化子 → コンストラクター初期化子 → コンストラクター本体の順になります。 また、変数初期化子は、メンバーの宣言順と同じ順序で呼び出されます。

セクション切ってもいいかも。

https://ufcpp.net/study/csharp/misc_construct.html 雑記あり。

ufcpp commented 1 year ago

https://ufcpp.net/study/csharp/misc_construct.html ちょっと修正。

ufcpp commented 1 year ago

属性 https://ufcpp.net/study/csharp/sp_attribute.html#primary-constructor

ufcpp commented 1 year ago

https://ufcpp.net/study/csharp/misc/analyzer-generator/#empty-body

ufcpp commented 1 year ago

https://ufcpp.net/study/csharp/oo_construct.html#primary-constructor

ufcpp commented 1 year ago

https://ufcpp.net/study/csharp/cheatsheet/ap_ver12/#primary-constructor