VB,C# 匿名クラス備忘録

業務にて、VBをC＃に変換する作業の際、匿名クラスの扱い方が少し異なり困ったので、それぞれの違いを含めて簡単にまとめます。
これまで自分は、JSのオブジェクトのようなものをVB,C#で定義したいときは、いちいち普通のクラスや構造体を定義、またはデータテーブル等に格納していたのですが、この匿名クラスも使えます。（状況によりますが）
他にも.Netにはデータ構造を生成するものとしてタプルなどもありますが、今回は匿名クラスのみをまとめます。

## 匿名クラスのざっくりとした基本（VB,C#共通）
* 名前のないクラスのようなもので、その場でインスタンスを生成できます
* クラスと同じで、参照型のデータになります
* クラスの型はコンパイラがコンパイル時に自動で型を付与します。この型はソースコードのレベルでは使用できません
* プロパティを作成できます
* プロパティの型は代入したオブジェクトの型になります。プログラマがあらかじめ定義することはできません


※C#、VB書き方は少し違います。以下がそれぞれの宣言方法です。
```C#:基本.cs
    var dog = new { Age = 5, Name="choco" };
    
    //これはエラーになります
    var dog = new { int Age = 5, string Name="choco" };
```
```VB:基本.vb
    'C#との違い １．Newの後にWithが必要。　２．プロパティの前に.も必要。
    Dim dog = New With {.Age = 5, .Name = "choco"}

    'VBも同様に以下はエラーになります
    Dim dog = New With {.Age As Integer  = 5, .Name As String = "choco"}
```

## 使い道
普通のクラスの使い分けとしては、ローカルスコープ内で一時的にデータを保存したい場合に、この匿名クラスを利用することが多いです。
例えば、Linqやforeachなどで、既存のコレクションに条件を付けて一時的に保存したい、というときです。
自分の職場での使用頻度としてはこの使い方が圧倒的でした。
このような場合は、確かに普通のクラスをそのためだけに定義するのは面倒なので使い勝手がいいです。
```C#:Linqの簡単な例.cs
    private class Cat
    {
        public string Name { get; set; } = string.Empty;
        public int Age { get; set; } = 0;
    }

    private void call(){
        List<Cat> listCat = new List<Cat> {
            new Cat() {Name="たま",Age=10 },
            new Cat() {Name="じじ",Age=0  },
            new Cat() {Name="こてつ",Age=0 }
        };
        
        var lstKitty = from cat in listCat
                       where cat.Age == 0
                       select new {cat.Name, cat.Age};
    }
```
```VB:Linqの簡単な例.vb
    Private Class Cat
        Public Property Name As String = ""
        Public Property Age As Integer = 0
    End Class

    Private Sub Call()
            Dim listCat As List(Of Cat) = New List(Of Cat) From {
                New Cat With {.Name="たま",.Age=10},
                New Cat With {.Name="じじ",.Age=0},
                New Cat With {.Name="こてつ",.Age=0}
            }
        
        '以下のように書くとKeyプロパティではない普通の匿名クラスになります
        'Keyプロパティについては後述しています
        Dim lstKitty = From cat In listCat
                       Where cat.Age = 0
                       Select New With {cat.Name, cat.Age}


        '以下のように書くと、Keyプロパティの匿名クラスになります
        Dim lstKitty2 = From cat In listCat
                        Where cat.Age = 0
                        Select cat.Name, cat.Age
End Sub              
```

## VBとC#の違い
##### (個人的に困ったところのみ抜粋です。）
C#の匿名クラスのプロパティは読み取り専用です。ですので以下のような処理はエラーが出ます。
![スクリーンショット 2024-02-21 113312.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3311139/b847685b-918f-87c4-965a-4f29034c20ab.png)


VBの場合はKeyプロパティに指定しているプロパティは、読み取り専用で、
そうでないプロパティは、書き込みもできてしまいます。
KeyプロパティとはVBの匿名クラスに用意されているキーワードで、プロパティを読み取り専用に指定します。
（他にも普通のプロパティとの違いはありますが、ここでは割愛します）

```vb:プロパティ.vb
'VBではKeyプロパティに指定していないプロパティは書き込みができる
Dim dog = New With {.Age = 5, .Name = "choco"}
dog.Age = 6

 'Keyプロパティに指定するとC#同様エラーになる
Dim keyDog = New With {Key .Age = 30, Key .Name = "choco"}
keyDog.Age = 31'ここでエラー
```

職場のVBのコードでは、"ある条件の場合だけプロパティの値を直接変更する"というプログラムを組んでいて、C#変換時に困りました。
C#でプロパティの値を変更したい場合は以下のようにwith式を使用します。
```C#:プロパティ.cs
var dog = new { Age = 5, Name="choco" };
var dog2 = dog with { Age = 6 };
```
## 所感
Linqなどでコレクションに条件を付けて一時格納したいときには便利な機能だということが分かりました。
まだまだ勉強中の身で、知らない機能もあるので、状況に応じたものを使いこなせるように知識と視野を広げていければ、と思います。

## 参考にさせていただきました
https://csharp.keicode.com/basic/anonymous-types.php
https://yaspage.com/cs-anonymous-type/