字典< T,Func&gt ;:如何将T用作Func的泛型类型? [英] Dictionary<T, Func>: how to use T as Func's generic type?

查看:73
本文介绍了字典< T,Func&gt ;:如何将T用作Func的泛型类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不知道如何清楚地表达它。

I didn't know how to express it clearly.

我有这个界面:

interface IConverter
{
    Dictionary<Type, Func<string, object>> ConversionMethods { get; }
}

基本上,它定义了一个合同,说实现它的类应该提供转换它使用的所有自定义类型的方法(它们是枚举还是其他)。

Basically, it defines a contract saying that a class implementing it should provide conversion methods for all the custom types it uses (be them enums or anything).

是否可以替换 object Func 的泛型类型及其相应的字典键的类型中(因此不可能有两个不匹配的类型)?

Is it possible to replace object in Func's generic types with its corresponding dictionary key's type (so it is impossible to have two unmatching types)?

我认为这是不可能的,但是替代方案有点烦人(使用 dynamic object ,创建专门的词典...)。

I think it's not possible, but the alternatives are a bit annoying (using dynamic or object, creating a specialized dictionary...).

编辑1:想象中的用法示例

edit 1: Imaginary exemple of use

interface IConverter
{
    Dictionary<Type, Func<string, object>> GetConversionMethods();
}

enum A
{
    AA,AB,AC
}

enum B
{
    BA, BB, BC
}

class blah : IConverter
{
    public Dictionary<Type, Func<string, object>> GetConversionMethods()
    {
        var d = new Dictionary<Type, Func<string, object>>
        {
            {
                typeof(A),
                (s) =>
                    {
                        // here, I could return whatever I want because the 'Func' returns 'object'
                        return s == "AA" ? A.AA : s == "AB" ? A.AB : A.AC;
                    }
            },
            {
                typeof(B),
                (s) =>
                    {
                        // same
                        return s == "BA" ? B.BA : s == "BB" ? B.BB : B.BC;
                    }
            }
        };
        return d;
    }

    void blahah()
    {
        // and here, I also get an `object`, where I would like to have a A
        GetConversionMethods()[typeof(A)]("123");
    }
}


推荐答案

首先,您需要将转换 Func 封装在其中类,这样您就可以更轻松地处理它们,而不必暴露它们所有不同的类型参数。然后,您需要定义接口或基类,以将各种通用参数隐藏在可能引起问题的位置,并允许您将不同的转换器放入同一集合中。然后,您将需要各种转换器在不直接使用这些类型参数的情况下发出信号指示它们使用哪种类型的方法。然后,您只需要使用一种方法将其包装在一个类中,该方法将根据需要找到合适的转换器。

First, you'll need to encapsulate the conversion Funcs inside classes, so that you can handle them more easily and without exposing all their differing type arguments. Then you'll need to define interfaces or base classes to hide the various generic arguments from places they'll cause problems, and allow you to put different converters in the same collection. Then, you'll need ways for the various converters to signal what types they work with without using those type arguments directly. Then you just need to wrap it all in a class with a method that'll find you the right converter on demand.

我将逐步指导您。

首先,此基类将是我们处理转换器的方式,而不必担心其泛型类型参数,但仍然知道其使用的类型。

First, this base class will be our way to handle a converter without worrying about its generic type arguments, but still know what types it work with.

public abstract class OneWayTypeConverterBase : IConvertFromType, IConvertToType
{
    public abstract Type AcceptsType { get; }
    public abstract Type ReturnsType { get; }
}

现在我们从该基类继承。这是进行转换实际工作的类。您可以使用可以执行所需转换操作的lambda实例化它。请注意,它实现了我们上面定义的属性。

Now we inherit from that base class. This is the class that does the actual work of converting; you can instantiate it with a lambda that does whatever conversion operation you need. Notice that it implements the properties we defined above.

public class OneWayTypeConverter<TSource, TTarget> : OneWayTypeConverterBase
{
    public OneWayTypeConverter(Func<TSource, TTarget> conversionMethod)
    {
        _conversionMethod = conversionMethod;
    }

    public override Type AcceptsType => typeof(TSource);
    public override Type ReturnsType => typeof(TTarget);

    private readonly Func<TSource, TTarget> _conversionMethod;

    public TTarget Convert(TSource sourceObject)
    {
        return _conversionMethod(sourceObject);
    }
}

现在我们需要一个地方来容纳所有这些,因此使用代码具有入口点。为简单起见,我将其收集在一个平面转换器中,然后将它们全部归档到嵌套字典中,以便稍后可以进行查找而不必调用所有 typeof

Now we need a single place to hold all of this, so that consuming code has an entry point. For simplicity, I had it take in a flat collection of converters, and then file them all into nested dictionaries so that it can do the lookups later without having to call typeof all the time.

public class TypeConverter
{
    public TypeConverter(IEnumerable<OneWayTypeConverterBase> converters)
    {
        _converters = converters
            .GroupBy(x => x.AcceptsType)
            .ToDictionary(
                kSource => kSource.Key,
                vSource => vSource
                    .ToDictionary(kTarget => kTarget.ReturnsType, vTarget => vTarget));
    }

    private Dictionary<Type, Dictionary<Type, OneWayTypeConverterBase>> _converters;

    public TTarget ConvertType<TSource, TTarget>(TSource sourceObject)
    {
        Dictionary<Type, OneWayTypeConverterBase> baseConverters;

        if (_converters.TryGetValue(sourceObject.GetType(), out baseConverters))
        {
            OneWayTypeConverterBase baseConverter;

            if (baseConverters.TryGetValue(typeof(TTarget), out baseConverter))
            {
                OneWayTypeConverter<TSource, TTarget> converter = baseConverter as OneWayTypeConverter<TSource, TTarget>;

                if (converter != null)
                {
                    return converter.Convert(sourceObject);
                }
            }

            throw new InvalidOperationException("No converter found for that target type");
        }
        else
        {
            throw new InvalidOperationException("No converters found for that source type");
        }
    }
}

现在,您可以设置像这样:

So now, you can set it up like this:

var converter = new TypeConverter(new List<OneWayTypeConverterBase>
{
    new OneWayTypeConverter<int, string>(x => $"The number was {x}"),
    new OneWayTypeConverter<int, bool>(x => x != 0),
    new OneWayTypeConverter<bool, string>(x => $"The bool was {x}")
});

然后只要需要,就可以像这样使用它:

and then whenever you need it, you can just use it like this:

var result = converter.ConvertType<int, string>(4);

这篇关于字典&lt; T,Func&gt ;:如何将T用作Func的泛型类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆