C# 中利用运行时编译实现泛函(2)

如果你的泛函库不能使在 C# 中完成泛型数学运算,没有人会对此买单。因此,接下里让我们处理这个问题。如果不能够修改 C# 原始数据类型去实现想要的接口,那么我们就创造另一种类型能够处理那些类型具有的所有数学运算。这就是在 .Net 框架中广泛使用的标准提供者模式。

边注/发泄:就我个人来说,我憎恨提供者模式。但我至今没有发现使用委托有处理不好的例子。当大量创建大量提供者时,他们没有使用委托。

当我们使用提供者模式,本质上仍是做和以前同样的事,但一个提供者类就能处理所有的数学运算。在EXAMPLE 4中检验它:

/EXAMPLE 4 ----------------------------------------
namespace ConsoleApplication

public class Program 
{   
public static void Main(string[] args)   
{     
Sum<int>(new int[] { 1, 2, 3, 4, 5}, new MathProvider_int());   
}    // (1) all the methods need access to the provider   
public static T
Sum<T>(T[] array, MathProvider<T> mathProvider)   
{     
T sum = mathProvider.GetZero();     
for (int i = 0; i < array.Length; i++)       
sum = mathProvider.Add(sum, array[i]);     
return sum;    } 
   
public interface MathProvider<T> 
{   
T GetZero(); // (2) you still need instance factory methods   
T Add(T left, T right); 

 public class MathProvider_int : MathProvider<int> 
{   
public MathProvider_int() { }   
int MathProvider<int>.GetZero()   
{     
return 0;   
}    // (3) you still have to implement each function for every single type     
int MathProvider<int>.Add(int left, int right)   
{     
return left + right;   

}
} // (4) can be slow depending on implementation (this version is slow)

EXAMPLE 4 通过把所有的泛函性质移动到帮助类中,我们可以使用C#基本类型执行数学运算。然而,这仅仅修复 EXMAPLE 3 中的第一个问题。我们仍旧需要解决以下问题:

所有方法都必须访问 mathProvider 类。虽然您可以编写代码,让其不必在每个函数间传递,这个原则同样适用于其它类似的结构。

你的实例化仍然基于工厂方法。在上面的情况中它是一个来自于int的转换。

在原始代码中你仍然需要为每一个简单的类型中实现泛函性。

这仍然相当慢,除非你为 provider 做一些”聪明的“缓存。provider 的传递和查找加起来真的很多。

现在我们已经尝试过在数值类型本身(EXAMPLE 3)和外部 provider(EXAMPLE 4)上使用接口。使用接口我们已经不能做更多了。可以确定的是我们可以运用一些聪明巧妙的存储方法,但最终仍会面临相同的问题:必须在每一步都支持定制的实现。

最后说一句...在 C# 中接口不适合用在高效的泛函计算中。

对象转换

在 C# 中所有事物都可以转换成 System.Object 类型。因此,我只要把每一个事物转换成一个对象然后用控制流处理它就可以了。让我们试一试。

Hide   Shrink   Copy Code

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/44fd2e25177d4cf95d97965a5212c7fd.html