C# 7.0から使えるようになった型スイッチを使用して、ちょっとだけ型安全なIValueConverterの実装を手軽にできるようにしてみる。
変換前後の型をつけたValueConverterBase
Convert関数
IValueConverterのConvert関数を実装する際に、switchを利用して型に一致した場合だけ型付きのConvert関数に処理を渡すようにする。配列にも対応しておくと便利。
// 継承クラスで実装する型Tから型UへのConvert関数
public abstract U Convert(T value, Type targetType, object parameter, string language);
// IValueConverterの実装
public object Convert(object value, Type targetType, object parameter, string language)
{
   switch (value)
    {
        case T t_val:
            return Convert(t_val, targetType, parameter, language);
        case IEnumerable<T> t_arr:
            return t_arr.Select(t => Convert(t, targetType, parameter,language));
        default:
            return null;
    }
}
ConvertBack関数
逆変換の関数もConvert関数と同じくswitchを利用する。
// 継承クラスで実装する型Uから型TへのConvertBack関数
public abstract T ConvertBack(U value, Type targetType, object parameter, string language);
// IValueConverterの実装
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
    switch (value)
    {
        case U u_val:
            return ConvertBack(u_val, targetType, parameter, language);
        case IEnumerable<U> u_arr:
            return u_arr.Select(u => ConvertBack(u, targetType, parameter, language));
        default:
            return null;
    }
}
ValueConverterBaseクラス全体
using System;
using System.Linq;
using System.Collections.Generic;
// TからUへの変換
public abstract class ValueConverterBase<T, U> : Windows.UI.Xaml.Data.IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        switch (value)
        {
            case T t_val:
                return Convert(t_val, targetType, parameter, language);
            case IEnumerable<T> t_arr:
                return t_arr.Select(t => Convert(t, targetType, parameter, language));
            default:
                return null;
        }
    }
    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        switch (value)
        {
            case U u_val:
                return ConvertBack(u_val, targetType, parameter, language);
            case IEnumerable<U> u_arr:
                return u_arr.Select(u => ConvertBack(u, targetType, parameter, language));
            default:
                return null;
        }
    }
    public abstract U Convert(T value, Type targetType, object parameter, string language);
    public abstract T ConvertBack(U value, Type targetType, object parameter, string language);
}
あと、parameterを型にしてもよいかもしれない。
使い方
BoolからVisibilityにするよくあるやつ
ヒントから「考えられる修正」で型付きのConvert関数をすぐ実装できるのが地味に便利。
自動生成されるthrow NotImplementExceptionを削除し、型にあわせてコードを書けば簡単にConverterの中身を実装できる。
using Windows.UI.Xaml;
public class BoolVisibilityConverter : ValueConverterBase<bool, Visibility>
{
    public override Visibility Convert(bool value, Type targetType, object parameter, string language)
    {
        return value ? Visibility.Visible : Visibility.Collapsed;
    }
    public override bool ConvertBack(Visibility value, Type targetType, object parameter, string language)
    {
        return value == Visibility.Visible;
    }
}
WPFの場合
using System;
using System.Globalization;
using System.Linq;
using System.Collections.Generic;
public abstract class ValueConverterBase<T, U> : System.Windows.Data.IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        switch (value)
        {
            case T t_val:
                return Convert(t_val, targetType, parameter, culture);
            case IEnumerable<T> t_arr:
                return t_arr.Select(t => Convert(t, targetType, parameter, culture));
            default:
                return null;
        }
    }
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        switch (value)
        {
            case U u_val:
                return ConvertBack(u_val, targetType, parameter, culture);
            case IEnumerable<U> u_arr:
                return u_arr.Select(u => ConvertBack(u, targetType, parameter, culture));
            default:
                return null;
        }
    }
    public abstract U Convert(T value, Type targetType, object parameter, CultureInfo culture);
    public abstract T ConvertBack(U value, Type targetType, object parameter, CultureInfo culture);
}
