C#7時代の依存関係プロパティと添付プロパティのコードスニペット

# 概要
VisualStudioには標準で依存関係プロパティと添付プロパティのコードスニペットが組み込まれています。
しかし、これらのコードスニペットは古くイマイチな部分があります。
そこで最新のC#7の文法に合わせた新しいコードスニペットを定義します。

とりあえず使ってみたい場合は最後の使用方法だけ参照ください。

# 新旧コードスニペット実行結果の比較
まず、VisualStudio組込バージョンと今回作ったNewバージョンの実行結果を比較します。

## 依存関係プロパティ

```csharp:propdp.snippet(VS組込)
public string Name
{
    get { return (string)GetValue(NameProperty); }
    set { SetValue(NameProperty, value); }
}

// Using a DependencyProperty as the backing store for Name.  This enables animation, styling, binding, etc...
public static readonly DependencyProperty NameProperty =
    DependencyProperty.Register("Name", typeof(string), typeof(ownerclass), new PropertyMetadata(""));
```

↓

```csharp:DependencyProperty.snippet(New)
#region Name依存関係プロパティ
public string Name
{
    get => (string)GetValue(NameProperty);
    set => SetValue(NameProperty, value);
}
public static readonly DependencyProperty NameProperty =
    DependencyProperty.Register(nameof(Name), typeof(string), typeof(MyClass), new PropertyMetadata(default(string)));
#endregion
```

## 添付プロパティ

```csharp:propa.snippet(VS組込)
public static string GetName(DependencyObject obj)
{
    return (string)obj.GetValue(NameProperty);
}

public static void SetName(DependencyObject obj, string value)
{
    obj.SetValue(NameProperty, value);
}

// Using a DependencyProperty as the backing store for Name.  This enables animation, styling, binding, etc...
public static readonly DependencyProperty NameProperty =
    DependencyProperty.RegisterAttached("Name", typeof(string), typeof(ownerclass), new PropertyMetadata(""));
```

↓

```csharp:AttachedProperty.snippet(New)
#region Name添付プロパティ
public static string GetName(DependencyObject obj) => (string)obj.GetValue(NameProperty);
public static void SetName(DependencyObject obj, string value) => obj.SetValue(NameProperty, value);
public static readonly DependencyProperty NameProperty =
    DependencyProperty.RegisterAttached("Name", typeof(string), typeof(MyClass), new PropertyMetadata(default(string)));
#endregion
```

# 変更点の解説
## regionで囲って見やすく 

```csharp
#region Name依存関係プロパティ
```

これは好みが分かれるところですが、複数の依存関係or添付プロパティが並んだ場合に読みやすくなります。
~~そもそもregionが必要になること自体が言語設計に問題があることを~~

## Get Set をExpression-bodiedに

```csharp
//依存関係プロパティ
get => (string)GetValue(NameProperty);

//添付プロパティ
public static string GetName(DependencyObject obj) => (string)obj.GetValue(NameProperty);
```

実はこのコードスニペット全体でC#7が必要なのは依存関係プロパティのgetterのみ

## コメント削除
依存関係プロパティ自体の説明を個別のプロパティの中に入れる必要性無いですよね。

## ownerclassが自動で現在のクラス名に

```csharp
DependencyProperty.Register(……, typeof(MyClass), ……
```

実行結果だけだと前と変わらないように見えますが、コードスニペットを実行した場所のクラス名が自動で入るようになりました。
後述するコードスニペット内の`<Function>ClassName()</Function>`の機能です。
コンストラクタのコードスニペット`ctor`と同じ動きです。

## nameof演算子（依存関係プロパティのみ）

```csharp
DependencyProperty.Register(nameof(Name), ……
```

文字列からnameof演算子にすることでより安全になります。

添付プロパティでも使用したかったのですが、そもそも添付プロパティには
`$プロパティ名$Property`はいても`$プロパティ名$`はいなかったので、できませんでした。

どうしても添付プロパティでも文字列指定を削除したい場合は
プロパティ名を取得するメソッドを別に用意して、引数にCallerMemberNameを使えばできます。

```csharp
public static readonly DependencyProperty AgeProperty =
    DependencyProperty.RegisterAttached(GetPropertyCoreName(), typeof(int), typeof(MyClass), new PropertyMetadata(default(int)));

private static string GetPropertyCoreName([CallerMemberName] string propName = null)
    => propName.Substring(0, propName.Length - "Property".Length);
```

## PropertyMetadata既定値を0からdefault(型)に変更

```csharp
DependencyProperty.Register(…… new PropertyMetadata(default(string)));
```

PropertyMetadataの既定値が型に関係なく常に`0`だったのを`default(型)`に変更
コードスニペットのLiteralのDefaultは他のLiteralの値を使用できないので、型名Literalを元にMetadata既定値にしています。

ただしMetadata既定値用のLiteralはDefaultを空にして残してあるので、既定値を変更したい場合はジャンプすることができます。

ちなみにうっかり以下のようにすると既定値がnullになります。

```csharp
DependencyProperty.Register(…… new PropertyMetadata(default));
```

# 使用方法
既存のコードスニペットを削除します。

場所は以下のところに書いてあります。
VisualStudio上Menu＞ツール＞コードスニペットマネージャ＞NetFX30

私の環境(VS2017)では以下の場所でした。
C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC#\Snippets\1041\NetFX30

次に以下2つのコードスニペットをファイルに保存してコードスニペットマネージャからインポートします。

[DependencyProperty.snippet-GitHub](https://raw.githubusercontent.com/soi013/CodeSnippetsForCSharp/master/CodeSnippets/DependencyProperty.snippet)
[AttachedProperty.snippet-GitHub](https://raw.githubusercontent.com/soi013/CodeSnippetsForCSharp/master/CodeSnippets/AttachedProperty.snippet)
# コードスニペット

```xml:DependencyProperty.snippet
<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets  xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <CodeSnippet Format="1.0.0">
    <Header>
      <Title>DependencyProperty</Title>
      <Shortcut>propdp</Shortcut>
      <Description>依存関係プロパティを作成します</Description>
      <Author>soi</Author>
      <SnippetTypes>
        <SnippetType>Expansion</SnippetType>
      </SnippetTypes>
    </Header>
    <Snippet>
      <Declarations>
        <Literal>
          <ID>type</ID>
          <ToolTip>プロパティの型</ToolTip>
          <Default>int</Default>
        </Literal>
        <Literal>
          <ID>property</ID>
          <ToolTip>プロパティ名</ToolTip>
          <Default>MyProperty</Default>
        </Literal>
        <Literal>
          <ID>ownerclass</ID>
          <Function>ClassName()</Function>
          <ToolTip>プロパティを登録している所有者の型</ToolTip>
          <Default>ignor this element</Default>
        </Literal>
        <Literal>
          <ID>defaultvalue</ID>
          <ToolTip>>PropertyMetadataの既定値</ToolTip>
          <Default></Default>
        </Literal>
      </Declarations>
      <Code Language="csharp">
        <![CDATA[
#region $property$依存関係プロパティ
public $type$ $property$
{
    get => ($type$)GetValue($property$Property);
    set => SetValue($property$Property, value);
}
public static readonly DependencyProperty $property$Property =
    DependencyProperty.Register(nameof($property$), typeof($type$), typeof($ownerclass$), new PropertyMetadata($defaultvalue$default($type$)));
#endregion
$end$]]>
      </Code>
    </Snippet>
  </CodeSnippet>
</CodeSnippets>

```


```xml:AttachedProperty.snippet
<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets  xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <CodeSnippet Format="1.0.0">
    <Header>
      <Title>AttachedProperty</Title>
      <Shortcut>propa</Shortcut>
      <Description>添付プロパティを作成します</Description>
      <Author>soi</Author>
      <SnippetTypes>
        <SnippetType>Expansion</SnippetType>
      </SnippetTypes>
    </Header>
    <Snippet>
      <Declarations>
        <Literal>
          <ID>type</ID>
          <ToolTip>プロパティの型</ToolTip>
          <Default>int</Default>
        </Literal>
        <Literal>
          <ID>property</ID>
          <ToolTip>プロパティ名</ToolTip>
          <Default>MyProperty</Default>
        </Literal>
        <Literal>
          <ID>ownerclass</ID>
          <Function>ClassName()</Function>
          <ToolTip>プロパティを登録している所有者の型</ToolTip>
          <Default>ignor this element</Default>
        </Literal>
        <Literal>
          <ID>defaultvalue</ID>
          <ToolTip>PropertyMetadataの既定値</ToolTip>
          <Default></Default>
        </Literal>
      </Declarations>
      <Code Language="csharp">
        <![CDATA[
#region $property$添付プロパティ
public static $type$ Get$property$(DependencyObject obj) => ($type$)obj.GetValue($property$Property);
public static void Set$property$(DependencyObject obj, $type$ value) => obj.SetValue($property$Property, value);
public static readonly DependencyProperty $property$Property =
    DependencyProperty.RegisterAttached("$property$", typeof($type$), typeof($ownerclass$), new PropertyMetadata($defaultvalue$default($type$)));
#endregion
$end$]]>
      </Code>
    </Snippet>
  </CodeSnippet>
</CodeSnippets>
```