WPF - 通用的IValueConverter?

5

我需要转换多个不同的对象,但我想避免为每个对象编写一个转换器类。每个对象都继承自基类,我需要使用ID来获取描述(这在我的CacheManager调用中处理)。

对于每个类(我大约有30个),我编写了以下代码:

object IValueConverter.Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
    Dictionary<int, string> codes = CacheManager.CodeLookup<CourtEventCode>();
    int id = 0;
    string result = string.Empty;

    if (int.TryParse(value.ToString(), out id) && id > 0)
    {
        if (codes.ContainsKey(id))
        {
            result = codes[id];
        }
        else
        {
            result = "Unknown";
        }
    }

    return result;
}

在上面的例子中,CourtEventCode 代表这个类的转换器。有没有一种方法可以从 IValueConverter.Convert 的 targetType 输入中派生该类,而不必将该类复制粘贴两打次呢?
谢谢,
Sonny
2个回答

2
这个答案提供了一种替代泛型的方法。
你可以使用代码生成器来加快速度,一次性创建所有类。 创建一个空的“TT”文件(你在新项目列表中看不到它,只需手动输入扩展名即可),单击警告对话框上的OK,然后将以下内容粘贴到其中。 从那里开始尝试操作,直到输出文件看起来正确。 每次保存TT文件时,输出文件都会被重新创建。
// The code in this CS file is auto-generated.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Data;

namespace WpfApplication
{

<#
    string[] classes = new string[]
        {"CourtEventCode", "SomeOtherCode", "WhatElseIsThere"};

    foreach (string classname in classes)
    {
#>
    public class <#= classname #>ValueConverter : IValueConverter
    {
        object IValueConverter.Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            Dictionary<int, string> codes = CacheManager.CodeLookup< <#= classname #> >();
            int id = 0;
            string result = string.Empty;

            if (int.TryParse(value.ToString(), out id) && id > 0)
            {
                if (codes.ContainsKey(id))
                {
                    result = codes[id];
                }
                else
                {
                    result = "Unknown";
                }
            }

            return result;
        }

        // Implement the rest of IValueConverter
    }

<# } #>
}

Yota,这是我的实际处理方法,但当我需要去改变基类时,那么我就必须要更新所有(已经)生成的代码。不太理想。 - Sonny Boy

1

是的,您可以使用反射调用 CacheManager.CodeLookup。

根据您分享的代码,代码应该如下所示:

Type containingType = typeof (CacheManager);
var method = containingType.GetMethod("CodeLookup", 
    BindingFlags.Static | BindingFlags.Public, null, new Type[0], new ParameterModifier[0]);
var concreteMethod = method.MakeGenericMethod(targetType);
Dictionary<string,int> codes = (Dictionary<string,int>)concreteMethod.Invoke(null, null);

如果您经常使用该方法,反射在性能方面可能会很昂贵,因此您可能希望为每个目标类型缓存concreteMethod实例。

编辑:当方法被重载时,为了匹配特定的重载,使用允许您指定确切参数并传递空数组(因为要调用的重载没有参数)的GetMethod重载。代码示例已更新。


我遇到了另一个问题……CodeLookup是一个重载方法,containingType.GetMethod在模糊匹配时抛出异常。我该如何指定反射器使用不带参数的方法? - Sonny Boy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接