C#のソースコードからPlantUMLのクラス図を生成するツール PlantUmlClassDiagramGenerator 1.3.0 をリリースしました！


# PlantUmlClassDiagramGenerator 1.3.0

C#のソースコードからPlantUMLのクラス図を生成するツールのversion 1.3.0 をリリースしました！
本バージョンから、生成元のソースコードに属性を付けることで、出力内容を柔軟に制御できるようになりました。

https://github.com/pierre3/PlantUmlClassDiagramGenerator

## VSCode Extension
Visual Studio Codeの拡張機能としても利用できます！

https://marketplace.visualstudio.com/items?itemName=pierre3.csharp-to-plantuml

## 属性を使ったカスタマイズ機能の追加
本ライブラリには元々プロパティやフィールドからクラス間の関連を自動生成する機能も付いているのですが、あまり細かい制御ができず使い勝手が良くありませんでした。

そこで、クラスやプロパティ、メソッドのパラメータなどに属性を付けることでクラス図への出力をある程度制御できるようにしました。

この機能を利用するには、各種属性が定義されているNuGetパッケージを対象のC#プロジェクトにインストールする必要があります。
https://www.nuget.org/packages/PlantUmlClassDiagramGenerator.Attributes

現在のところ、下記属性が定義されています。
- PlantUmlAssociationAttribute  
  クラス間の関連付けの詳細を指定できます
- PlantUmlDiagramAttribute
  この属性を付けた型(class,structなど)のみが出力対象となります。コマンドラインオプション -attributeRequired が指定された場合のみ有効。
- PlantUmlIgnoreAttribute
  この属性を付けた要素は出力対象外となります。
- PlantUmlIgnoreAssociationAttribute
  プロパティやフィールドに付けると、クラス間の関連ではなくクラスのメンバーとして出力されます。

### PlantUmlAssociationAttribute
この属性を追加することでクラス間の関連付けを細かく指定することができます。
関連の種類（composition, aggregation, dependency など）を指定したり、多重度を追記することも可能です。

```csharp
using PlantUmlClassDiagramGenerator.Attributes;
class User
{
    public string Name { get; set; }
    public int Age { get; set; }
}
    
class ClassA
{
    [PlantUmlAssociation(Association = "--", RootLabel = "RootLabel" Label = "Label", LeafLabel = "LeafLabel")]
    public Item Prop { get; set; }
}

class ClassB
{
    [PlantUmlAssociation(Name = "User", Association = "o-->", RootLabel = "1", Label = "IList<User>", LeafLabel = "0..1")]
    public IList<User> Users { get; set; }
}
```

属性値で指定された通りに関連が追加されます。

```csharp
@startuml
class User {
    + Name : string <<get>> <<set>>
    + Age : int <<get>> <<set>>
}
class ClassA {
}
class ClassB {
}
ClassA "RootLabel" -- "LeafLabel" Item : "Label"
ClassB "1" o--> "0..1" User : "IList<User> : Users"
@enduml
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28805/aadb8dae-3ade-f2a0-6142-8a13763bc9b2.png)

属性が利用できなかった以前では、下記の様な出力結果となり、コレクションの関連がうまく表現できませんでした。

```
@startuml
class User {
    + Name : string <<get>> <<set>>
    + Age : int <<get>> <<set>>
}
class ClassA {
}
class ClassB {
}
class "IList`1"<T> {
}
ClassA --> "Prop" Item
ClassB --> "Users<User>" "IList`1"
@enduml
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28805/c54d118d-d7ee-da74-ebcc-fef5dc079c8a.png)

また、この属性はメソッドのパラメータに対しても付与することが可能です。
```csharp
class ClassA
{
   private ILogger logger;
   public ClassA([PlantUmlAssociation(Association = "-->", Label = "Injection")] ILogger logger)
   {
        this.logger = logger;
   }
}
```

```
@startuml
class ClassA {
    + ClassA(logger:ILogger)
}
ClassA --> ILogger : "Injection"
@enduml
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28805/6328b86e-484a-f82d-cdbd-035bccaf39f4.png)

これで、より柔軟な表現ができるようになったと思います。


### PlantUmlDiagramAttribute
この属性は、クラス数の多い大規模プロジェクトなどで必要なクラス図だけを出力したい場合に便利です。
今回新しく追加されたコマンドラインオプション `-attributeRequired` と組み合わせて使用します。

```csharp
[PlantUmlDiagram]
interface IInterfaceA 
{
    void MethodA();
}

class ClassA
{
    public string PropA { get; set; }
}

[PlantUmlDiagram]
class ClassB : IInterfaceA
{
    public string PropA { get; set; }
    public void MethodA();
}


struct StructA
{
    public string PropA { get; set; }
}
```

`-attributeRequired`オプションを付けて実行すると、`PlantUmlDiagramAttribute`でマークしたクラス、インターフェイスのみが出力されます。

```
@startuml
interface IInterfaceA {
    MethodA() : void
}
class ClassB {
    + PropA : string <<get>> <<set>>
    + MethodA() : void
}
IInterfaceA <|-- ClassB
@enduml
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28805/9e4f47c7-0d65-f50b-c00d-90d2d37ec5a3.png)

### PlantUmlIgnoreAttribute

この属性は、出力させたくない要素に付与します。
クラス・インターフェイスなどの型、プロパティ、フィールド、メソッドの単位で付けることができます。

```csharp
[PlantUmlIgnore]
class ClassA
{
    public string PropA { get; set; }
    public void MethodA();
}

class ClassB
{
    [PlantUmlIgnore]
    public string PropA { get; set; }
    public string PropB { get; set; }
    [PlantUmlIgnore]
    public void MethodA();    
    public void MethodB();
}
```

```
@startuml
class ClassB {
    + PropB : string <<get>> <<set>>
    + MethodB() : void
}
@enduml
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28805/3fd99937-57ec-42b2-2119-3927909592cb.png)

### PlantUmlIgnoreAssociationAttribute

コマンドラインオプション `-createAssociation` を有効にすると、プロパティやフィールドの定義がクラス図から外に出されて、クラス間の関連として出力されます。
この属性を付けたプロパティやフィールドは、関連としてではなくメンバーとしてクラス内に記述されるようになります。

```csharp
class Item
{
}

class ClassA
{
    public Item PropA { get; set; }
    public Item PropB { get; set; }
}

class ClassB
{
    [PlantUmlIgnoreAssociation]
    public Item PropA { get; set; }
    [PlantUmlIgnoreAssociation]
    public Item PropB { get; set; }
}
```

```
@startuml
class Item {
}
class ClassA {
}
class ClassB {
    + PropA : Item <<get>> <<set>>
    + PropB : Item <<get>> <<set>>
}
ClassA --> "PropA" Item
ClassA --> "PropB" Item
@enduml
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28805/ef523f7c-00ec-35cd-f377-67c1e6998546.png)

# おわりに
今回追加した属性によるカスタマイズ機能は、もう少し時間をかけてブラッシュアップしていく予定です。
この記事を見て気になった方がいらっしゃいましたら是非一度使ってみてください！
また、ご意見・ご要望などいただけますと大変うれしいです。