本文介绍了通用委托列表(例如System.Converter< TInput,TOutput>)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否可以创建通用委托的列表,例如 System.Converter< TInput,TOutput> ?

Is it possible to create a list of generic delegates, like System.Converter<TInput, TOutput>?

在Java中,它可能是 List< Converter<?,?>> ,但是使用Java的类型擦除并不是很有用.似乎在C#中,应该可以从列表中检索到泛型类型,然后使用获得的实例执行所需的转换.

In java that could be List<Converter<?,?>>, but with Java's type erasure that's not very useful. Seems like in C# it should be possible to query the generic types after retrieval from the list and use the obtained instance to perform the desired conversion.

详细说明问题:
我有用户提供的格式的用户提供的数据,在编译时我一无所知.当然,我程序中的算法知道如何使用其自己的特定数据类型.目标是要具有与Java等效的 List< Converter<?,?>> ,在其中可以安装Converter(由我或用户)并由程序自动查询以查看用户的数据可以转换为算法所需的格式.

Elaborating on the question:
I have user supplied data in user provided formats which I know nothing about at compile time. Algorithms in my program know how to work with its own specific data types, of course. The goal is to have an equiavalent of Java's List<Converter<?,?>> where Converters can be installed (by me, or users) and queried automatically by the program to see if user's data can be converted to the required format for an algorithm.

推荐答案

这是非常基本的内容,仅用于显示基本概念.

This is very rudimentary and is only intended to show the basic concept.

它具有:

  • 在输入和输出类型的2个元组上键入关键字的字典,以保存转换器实例.
  • 用于注册转换器的 Register 方法.注册相同的类型对将覆盖先前注册的转换器.您可以轻松地将其更改为无操作或例外.
  • Convert 方法以调用已注册的转换器.如果需要,创建一个 TryConvert 方法将非常简单.
  • A dictionary keyed on a 2-tuple of input and output types to hold converter instances.
  • A Register method to use for registering converters. Registering the same pair of types overwrites a previously registered converter. You can easily change it to be a no-op or an exception.
  • A Convert method to call a registered converter. It would be very trivial to create a TryConvert method if you needed it.
public static class ConverterContainer
{
    private static readonly Dictionary<(Type, Type), Delegate> _converters = new Dictionary<(Type, Type), Delegate>();

    public static void Register<TInput, TOutput>(Func<TInput, TOutput> converter)
    {
        if (converter is null)
            throw new ArgumentNullException(nameof(converter));

        _converters[(typeof(TInput), typeof(TOutput))] = converter;
    }

    public static TOutput Convert<TInput, TOutput>(TInput input)
    {
        if (_converters.TryGetValue((typeof(TInput), typeof(TOutput)), out var del))
        {
            Func<TInput, TOutput> converter = (Func<TInput, TOutput>)del;

            return converter(input);
        }

        throw new InvalidOperationException("Converter not registered.");
    }
}

没有的内容:

  • 线程安全.这留给认真的实现者练习.
  • 可能我没有花时间考虑的其他事情.

如何使用它:

在应用程序启动时,注册转换器,例如注册用于依赖项注入的服务.

At startup of your application, register converters, like registering services for dependency injection.

ConverterContainer.Register<long, int>(l => (int)l);
// ... etc.

以及要在一对已注册的输入/输出类型之间进行转换的位置:

And wherever you want to perform conversion between a registered pair of input/output types:

int x = ConverterContainer.Convert<long, int>(1000L)

不幸的是,您必须在此处指定两个类型参数.

Unfortunately, you do have to specify both type arguments here.

从OP添加:

不必指定输入参数类型(这是具有可用转换的动态列表的关键),请在上面的示例 ConverterContainer 中使用以下其他方法(因为@madreflection具有在自己的评论中建议):

To not have to specify the input parameter type (which is kind of the point of having a dynamic list of available conversions) use the following additional method in the sample ConverterContainer above (as @madreflection has suggested in the comments himself) :

public static TOutput Convert<TOutput>(object toConvert) {
    if (toConvert is null)
        throw new ArgumentNullException(nameof(toConvert));

    if (Converters.TryGetValue((toConvert.GetType(), typeof(TOutput)), out Delegate conv)) {
        object o = conv.DynamicInvoke(toConvert);
        return (TOutput) o;
    }

    throw new InvalidOperationException($"Converter not registered for types: {toConvert.GetType().Name} -> {typeof(TOutput).Name}");
}

您现在可以放入任何随机的 object 实例,看看是否可以转换为所需的类型.

You can now throw in any random object instance and see if the conversion to your desired type is possible.

这篇关于通用委托列表(例如System.Converter&lt; TInput,TOutput&gt;)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-26 23:00