【问题标题】:WPF - Generic IValueConverter?WPF - 通用 IValueConverter?
【发布时间】:2010-09-08 16:27:27
【问题描述】:

我需要转换许多不同的对象,我想避免为每个对象编写一个转换器类。每个对象都继承自一个基类,我需要使用 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 输入派生该类,而不必基本上复制和粘贴该类两次?

提前致谢,
桑尼

【问题讨论】:

    标签: c# .net wpf generics converter


    【解决方案1】:

    这个答案是泛型的替代品。

    您可以使用代码生成器一次性创建所有类来帮助加快速度。创建一个空白的“TT”文件,(您不会在新项目列表中看到它,只需手动输入扩展名。)在警告对话框上单击“确定”,然后将其粘贴到其中。从那里开始,直到输出文件看起来正确。每次保存 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,这是我实际采用的方法,但是当我需要更改基类时,我必须更新所有(已经)生成的代码。不理想。
    【解决方案2】:

    是的,您可以使用反射调用 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);
    

    如果您经常使用该方法,也许您会希望为每个 targetType 缓存 concreteMethod 实例,就性能而言,反射可能代价高昂。

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

    【讨论】:

    • 我遇到了另一个问题... CodeLookup 是一个重载的方法,containingType.GetMethod 为不明确的匹配抛出异常。如何指定反射器使用不接受争论的方法?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-14
    • 2010-09-15
    相关资源
    最近更新 更多