C#4.0 dynamic:一个潜在的性能解决方案数值泛型? [英] C# 4.0 dynamic: A potential performant solution to numeric generics?

查看:231
本文介绍了C#4.0 dynamic:一个潜在的性能解决方案数值泛型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在尝试在C#中实现一个通用的 Vector2< int / float / double> 后,我对这个问题进行了一系列调查问题,也在此问题中描述:

After coming up against this problem myself in trying to implement a generic Vector2<int/float/double> in C#, I've done a bunch of investigation into this problem, also described in this question:

Less generic generics? A possible solution for arithmetic in C# generics

这些链接包含一些更多的背景信息和迷人的解决方案:

These links contain some more background information and fascinating solution approaches:

http://www.yoda.arachsys.com/csharp/genericoperators.html

http://www.codeproject.com/KB/ cs / genericnumerics.aspx

现在C#4.0已经出现了新的多功能动态类型,我对于辉煌的SO社区的问题是:这是一个可用于构建高性能的矢量/矩阵等的工具。数字类型?

Now that C# 4.0 is out with its new versatile dynamic type, my question for the brilliant SO community, is this: is it a tool that could be used perhaps to build performant, generic Vector/Matrix/etc. numeric types?

很明显,Vector2可以这样构建:

Clearly a Vector2 could be built by simply like so:

public struct Vector2
{
    public dynamic X;
    public dynamic Y;

    public Vector2(dynamic x, dynamic y)
    {
        this.X = x;
        this.Y = y;
    }

    public static Vector2 operator+(Vector2 a, Vector2 b)
    {
        return new Vector2(a.X + b.X, a.Y + b.Y);
    }
}

但是使用这种方法我们没有类型约束,所以你可以使 Vector2(3,12.4572)。有一种方法,我们可以混合动态成员与一个类型参数 Vector2< int> 来执行我们的数学操作,就像使用 int s?

but with this approach we have no type constraint here, so you could make a Vector2(3, 12.4572). Is there a way that we could mix dynamic members with a type parameter Vector2<int> to perform our math operations as would be done with ints?

也许某种形式的转换可以用来确保 this.X T ,但我不知道该如何执行。

Perhaps some form of casting could be used to ensure this.X is a T, though I don't know how that would perform.

推荐答案

只有你可以知道动态操作符调用是否会满足你的性能要求,但是肯定可以用泛型来解决你的一些类型安全问题 - 没有理由必须在运行时检查所有 时间只是因为一个动态调用:

Only you can tell if dynamic operator invocations will meet your performance requirements, but it's certainly possible to address some of your type-safety concerns with generics - there's no reason that everything has to be checked at run-time just because of one little dynamic call:

// Consider making this type immutable
public struct Vector2<T>
{
    public T X;
    public T Y;

    public Vector2(T x, T y)
    {
        this.X = x;
        this.Y = y;
    }

    //  The only dangerous operation on the type
    public static Vector2<T> operator +(Vector2<T> a, Vector2<T> b)
    {
        return new Vector2<T>((dynamic)a.X + b.X, (dynamic)a.Y + b.Y);
    }
}

现在,唯一危险的操作是> add 2个相同类型的向量(加法运算符需要在类型参数上按预期工作),但是其他一切都是完全类型安全的,因为它应该是。您不能新的Vector< int>(a,5),添加 Vector< int> Vector< string> ,或者将两个 Vector 的添加分配给 Vector< string> 。请注意,这些错误不会在编译时被您的原始解决方案捕获。

Now, the only dangerous operation is to actually add 2 vectors of the same type (the addition operator needs to work as expected on the type-argument), but everything else is perfectly type-safe, as it should be. You can't do new Vector<int>("a", 5), add a Vector<int> and a Vector<string>, or assign the addition of two Vector<int>s to a Vector<string>. Note that none of these errors would have been caught at compile-time with your original solution.

请注意:


  1. 没有什么可以阻止你在这里使用泛型沿着compiling-an-expression-tree路径添加,而不是 dynamic 。代理调用不是免费的,但是在理论上它们应该比 dynamic 方法更快 - 至少,避免使用boxing值类型。

  1. There's nothing to stop you from using generics here but going down the compiling-an-expression-tree route for the addition instead of dynamic. Delegate invocations aren't free, but they should in theory be faster than the dynamic approach in this case - at the very least, you avoid boxing value-types. Only you can tell if they will be fast enough, though.

在所有情况下,请考虑编写一个静态构造函数,类型参数实际上具有适当的加法运算符,使得类型错误在游戏早期发生。

In all cases, consider writing a static-constructor that validates that the type-argument in fact has a suitable addition operator, so that type-errors happen early on in the game.






EDIT 满足动态的性能):

表达式树方法看起来像: p>

The expression-tree approach would look something like:

public struct Vector2<T>
{
    private static readonly Func<T, T, T> Add;

    // Create and cache adder delegate in the static constructor.
    // Will throw a TypeInitializationException
    // if you can't add Ts or if T + T != T 
    static Vector2()
    {
        var firstOperand = Expression.Parameter(typeof(T), "x");
        var secondOperand = Expression.Parameter(typeof(T), "y");
        var body = Expression.Add(firstOperand, secondOperand);
        Add = Expression.Lambda<Func<T, T, T>>
              (body, firstOperand, secondOperand).Compile();
    }

    public T X;
    public T Y;

    public Vector2(T x, T y)
    {
        this.X = x;
        this.Y = y;
    }

    public static Vector2<T> operator +(Vector2<T> a, Vector2<T> b)
    {
        // Delegate invocation instead of dynamic operator invocation.
        return new Vector2<T>(Add(a.X, b.X), Add(a.Y, b.Y));
    }
}

这篇关于C#4.0 dynamic:一个潜在的性能解决方案数值泛型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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