模拟代表在C#免费泛型类型参数 [英] Emulating delegates with free generic type parameters in C#

查看:161
本文介绍了模拟代表在C#免费泛型类型参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是关于语言设计,模式和语义一个很难回答的问题。请不要向下票,因为你看不到的实用价值。

This is a hard question about language design, patterns and semantics. Please, don't down-vote just because you don't see the practical value.

首先,让我们想想功能及其参数。然后,我们来看看他们的参数/参数和与它们的类型参数/类型参数泛型类/函数的函数之间的类比。

First, let's think about functions and their parameters. Then we'll look at the analogies between functions with their parameters/arguments and generic classes/functions with their type-parameters/type-arguments.

功能与部分称为未指定的值的代码块的参数的。
你提供的参数的和接受的结果。

Functions are blocks of code with some unspecified values called "parameters". You supply the arguments and receive the result.

泛型类与一些不明班的类型参数的。
你提供的类型参数的,然后你可以用类工作 - 调用构造函数或调用静态方法

Generic classes are classes with some unspecified "type-parameters". You supply the type-arguments and then you can work with the class - call the constructor or invoke static methods.

< STRONG>泛型函数在非泛型类有一些不确定的功能的类型参数的,有的未指定的值参数的。
你提供的类型参数的和的值参数的接收效果。

Generic functions in non-generic classes are functions with some unspecified "type-parameters" and some unspecified "value-parameters". You supply the type-arguments and value-arguments to receive result.

代表是指向特定的功能。当你创建委托你不指定功能的参数的,但后来他们提供

Delegates are pointers to specific functions. When you create delegate you don't specify the function arguments, but supply them later.

的问题是,.NET不具备对于未指定的通用的类型参数的泛型函数代表的等价的。您不能提供的类型值的的的类型参数的后面。
我们可以设想,不仅有免费的值的参数的,而且还是免费的类型参数的代表。

The problem is that .Net doesn't have equivalent of Delegates for generic functions with unspecified generic type-parameters. You cannot supply type-values for the type-parameters later. We can imagine delegates that have not only free value parameters, but also free type-parameters.

static class SomeClass {
    //generic function
    public static T GetValue<T>() {
        return default(T);
    }
}

//creating delegate to generic function or method group
Func{TFree}<TFree> valueFactory = SomeClass.GetValue;

//creating delegate to anonymous generic function
Func{TFree}<int, List<TFree>> listFactory = {TFree}(int capacity) => new List<TFree>(capacity);



下面是我想在C#编写一个程序[伪]代码。我想知道如何能够实现在一个正确的C#程序中的类似行为。

Below is the [pseudo]code for a program that I want to write in C#. I want to know how one can achieve the similar behavior in a correct C# program.

我们如何能够效仿,免费泛型类型参数的代表在C#?

我们如何能够通过参考/链接泛型函数[S]与尚未未知的泛型参数通过非通用代码?

public static class Factory { //Everything compiles fine here
    public delegate ICollection<T> FactoryDelegate<T>(IEnumerable<T> values);

    public static ICollection<T> CreateList<T>(IEnumerable<T> values) {
        return new List<T>(values);
    }

    public static ICollection<T> CreateSet<T>(IEnumerable<T> values) {
        return new HashSet<T>(values);
    }
}

public class Worker { //non-generic class
    Func{TFree}<FactoryDelegate<TFree>> _factory; //TFree is a "free" generic type paramenter

    public Worker(Func{TFree}<FactoryDelegate<TFree>> factory) {
        _factory = factory;
    }

    public ICollection<T> DoWork<T>(IEnumerable<T> values) { //generic method
        return _factory{T}(values); //supplying T as the argument for type parameter TFree
    }
}

public static class Program {
    public static void Main() {
        string[] values1 = new string[] { "a", "b", "c" };
        int[] values2 = new int[] { 1, 2, 2, 2 };

        Worker listWorker = new Worker(Factory.CreateList); //passing reference to generic function
        Worker setWorker = new Worker(Factory.CreateSet); //passing reference to generic function

        ICollection<string> result1 = listWorker.DoWork(values1);
        ICollection<int> result2 = listWorker.DoWork(values2); //.Count == 4
        ICollection<int> result3 = setWorker.DoWork(values2); //.Count == 2
    }
}

请参阅我们如何通过不指定的类型参数的泛型函数(Factory.CreateList和Factory.CreateSet),以工人类的构造函数的引用?的类型参数的稍后时提供通用DoWork的函数调用具体类型的数组。 DoWork的使用的类型参数的选择正确的功能,传球的值参数的给它,并返回接收到的值。

See how we pass the references to generic functions (Factory.CreateList and Factory.CreateSet) to the Worker class constructor without specifying the type arguments? Type arguments are supplied later when the generic DoWork function is called with concrete-typed arrays. DoWork uses the type-arguments to select the correct function, passes value-arguments to it and returns the received value.

最终的解决方案:仿效了免费泛型类型参数的代表在C#

推荐答案

我觉得你的方式效仿这一在语言不使用委托,但接口。非通用接口可以包含一个通用的方法,这样你可以得到最开放的类型参数代表的行为。

I think the way you emulate this in the language is by not using delegates but interfaces. A non-generic interface can contain a generic method, so you can get most of the behavior of delegates with open type arguments.

下面就是你们的榜样重新加工成有效的C#程序(请注意,它仍然需要你定义的工厂类):

Here is your example re-worked into a valid C# program (Note that it still requires the Factory class you defined):

public interface IWorker
{
    ICollection<T> DoWork<T>(IEnumerable<T> values);
}

public class ListCreationWorker : IWorker
{
    public ICollection<T> DoWork<T>(IEnumerable<T> values)
    {
        return Factory.CreateList<T>(values);
    }
}

public class SetCreationWorker : IWorker
{
    public ICollection<T> DoWork<T>(IEnumerable<T> values)
    {
        return Factory.CreateSet<T>(values);  
    }
}

public static class Program {
    public static void Main(string[] args) {
        string[] values1 = new string[] { "a", "b", "c" };
        int[] values2 = new int[] { 1, 2, 2, 2 };

        IWorker listWorker = new ListCreationWorker();
        IWorker setWorker = new SetCreationWorker();

        ICollection<string> result1 = listWorker.DoWork(values1);
        ICollection<int> result2 = listWorker.DoWork(values2); //.Count == 4
        ICollection<int> result3 = setWorker.DoWork(values2); //.Count == 2
    }
}

public static class Factory
{
    public static ICollection<T> CreateSet<T>(IEnumerable<T> values)
    {
        return new HashSet<T>(values);
    }

    public static ICollection<T> CreateList<T>(IEnumerable<T> values)
    {
        return new List<T>(values);
    }
}

您仍然得到分离的决定的重要特征从该方法的执行调用哪个方法。

You still get the important feature of separating the decision of which method to call from the execution of said method.

一件事,你不能这样做,但是,是存储在该 IWorker <任何状态/ code>在一个通用的方式实现。我不知道怎么说可能是有用的,因为的DoWork 方法可以使用​​不同类型参数每次调用。

One thing that you cannot do, however, is store any state in the the IWorker implementations in a generic fashion. I'm not sure how that could be useful because the DoWork method could be called with different type arguments every time.

这篇关于模拟代表在C#免费泛型类型参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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