Help us understand the problem. What is going on with this article?

IValueConverterの実装は型付きのBaseを作っておくと便利

More than 1 year has passed since last update.

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関数をすぐ実装できるのが地味に便利。

boolvisibility.png

自動生成される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);
}
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした