设为首页 加入收藏

TOP

C# 中利用运行时编译实现泛函(二)
2015-07-16 12:56:08 来源: 作者: 【 】 浏览:13
Tags:利用 行时 编译 实现
provider? ?
public static T
Sum(T[] array, MathProvider 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 GetZero(); // (2) you still need instance factory methods? ?
T Add(T left, T right);?
}?
?public class MathProvider_int : MathProvider?
{? ?
public MathProvider_int() { }? ?
int MathProvider.GetZero()? ?
{? ? ?
return 0;? ?
}? ? // (3) you still have to implement each function for every single type? ? ?
int MathProvider.Add(int left, int right)? ?
{? ? ?
return left + right;? ?
}?
}
} // (4) can be slow depending on implementation (this version is slow)


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


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


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


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


Hide ? Shrink ? Copy Code


// EXAMPLE 5 ----------------------------------------
namespace ConsoleApplication
{?
public class Program?
{? ?
public static void Main(string[] args)? ?
{? ? ?
MathProvider.Sum(new int[] { 1, 2, 3, 4, 5});? ?
}?
}?
public static class MathProvider?
?{? ?
public static T Sum(T[] array)? ?
{? ? ? // (1) still requires a custom implementation for every type? ? ?
if (typeof(T) == typeof(int))? ? ?
{? ? ? ?
T sum = (T)(object)0; // (2) largescale casting is very glitch prone? ? ? ?
for (int i = 0; i < array.Length; i++)? ? ? ? ?
sum = (T)(object)((int)(object)sum + ((int)(object)array[i]));? ? ? ?
return sum;? ? ? }? ? ? t
hrow new System.Exception("UNSUPPORTED TYPE"); // (3) runtime errors? ?
}? } }
// (4) horribly slow...


事实是,这看起来要比接口化方法好。代码很简单并且容易使用。然而,和以前一样我们还是有很多问题:


注:我不知道他们是否仍然在用 F# 来做这个,但是当我浏览 F# 中一般的标准数学函数时,他们所做的看起来像是最低水平的对象转换。可笑至极!


对象转换是另一个死胡同,但它至少非常简单易用。


代理


代理......真的很棒!


我们不能像使用原始类型那样高效地完成数学运算。如果没有每种继承关系编译器将不能作出判断,并且我们也不能让C#的原始类型继承我们自己的类。


所以,我们把一般类外的一般代码的功能都移除吧。我们需要怎么做呢?代理!只要在一般的类里设置一个代理,并在运行时从外部分配,这些类型就能够被编译器所识别。


然而,我们可以把委托(代理)放到泛型类中,在外部编译委托(代理)然后在运行时分配。


Hide ? Shrink ? Copy Code


EXMAPLE 5 是目前最好的泛函例子。它运行很快,适用于任何类型,并且除了要确保静态构造方法必须被调用外很容易使用。但是,它仍有一些瑕疵...(1)构造方法必须被调用,(2)对每一个类型依旧须要自定义一个实现,(3)还会抛出运行时错误。


在这一点上我们必须做出一些妥协。首先,运行时异常时几乎不可避免的。我能想到的唯一方法是制作一个自定义插件加入到 Visual Studio 中那将会抛出额外的编译错误。那为了这篇文章的目的,就必须处理这个运行时异常。然而最大的问题是我们还是要为我们需要支持的每一个给类型写一个函数。一定会有解决这个问题的办法!


这是我目前的一个通用的数学模式的版本:


using Microsoft.CSharp; using System;
using System.CodeDom.Compiler;
using System.Reflection;
namespace RuntimeCodeCompiling {?
public static class Program?
{? ?
public static Action action;? ?
public static void Main(string[] args)? ?
{? ? ?
Console.WriteLine("Sum(double): " + Generic_Math.Sum(new double[] { 1, 2, 3, 4, 5 }));
Console.WriteLine("Sum(int): " + Generic_Math.Sum(new int[] { 1, 2, 3, 4, 5 }));? ? ?
Console.WriteLine("Sum(decimal): " + Generic_Math.Sum(new decimal[] { 1, 2, 3, 4, 5 }));? ? ?
Console.ReadLine();? ?
}? ?
#region Generic Math Library Example? ?
public static class Generic_Math? ?
{? ? ?
public static Func Sum = (T[] array) =>? ? ?
{ // This implementation will make this string be stored in memory during runtime,
//so it might be better to read it from a file? ? ? ?
string code = "(System.Func)((NUMBER[] array) =>
{ NUMBER sum = 0; for (int i = 0; i < array.Length; i++) sum += array[i]; return sum; })";? ? ? ?
// This requires that "T" has an implicit converter from int values and a "+" operator? ? ? ?
code = code.Replace("NUMBER", typeof(T).ToString());? ? ? ?
// This small of an example requires no namspaces or references? ? ? ?
Generic_Math.Sum = Generate.Object>(new string[] { }, new string[] { }, code);
return Generic_Math.Sum(array);? ? ?
};? ?
}? ?
///

Generates objects at runtime.? ?
internal static class Generate? ?
?{
/// Generates a generic object at runtime.? ? ?
/// The type of the generic object to create.? ? ?
/// The required assembly references.? ? ?
/// The required namespaces.? ? ?
/// The object to generate.? ? ?
/// The generated object.? ? ?
internal static T Object(string[] references, string[] name_spaces, string code)? ? ?
{
string full_code = string.Empty;? ? ? ?
if (name_spaces != null)? ? ? ? ?
for (int i = 0; i < name_spaces.Length; i++)? ? ? ? ? ?
full_code += "using " + name_spaces[i] + ";";? ? ? ?
full_code += "namespace Seven.Generated
{";? ? ? ?
full_code += "public class Generator
{";? ? ? ?
full_code += "public static object Generate()
{ return " + code + "; } } }";? ? ? ?
CompilerParameters parameters = n
首页 上一页 1 2 3 下一页 尾页 2/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇使用 FFmpeg 处理高质量 GIF 图片 下一篇深入理解JavaScript new的机制

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: