.net 如何获取表达式参数的数组长度

jei2mxaa  于 2023-01-18  发布在  .NET
关注(0)|答案(3)|浏览(156)

此方法应返回一个函数,该函数可以计算两个大小相同的向量的标量积:

public static Func<T[], T[], T> GetVectorMultiplyFunction<T>() where T : struct
{
    var x = Expression.Parameter(typeof(T[]), "x");
    var y = Expression.Parameter(typeof(T[]), "y");

    var body = Enumerable
        .Range(0, 3 /*Expression.ArrayLength(x)*/)
        .Select(i => Expression.Multiply(
            Expression.ArrayIndex(x, Expression.Constant(i)),
            Expression.ArrayIndex(y, Expression.Constant(i))
        ))
        .Aggregate(Expression.Add);

    var lambda = Expression.Lambda<Func<T[], T[], T>>(body, x, y);

    return lambda.Compile();
}

但为了做到这一点,我需要知道数组的长度,有一个方法Expression.ArrayLength()返回UnaryExpression而不是int,并且表达式不能显式地转换为int,有没有一种方法可以事先将数组长度计算为int

统一采购司

下面是一个单元测试,展示了该方法的工作原理:

[Test]
public void GetVectorMultiplyFunctionReturnsFunctionForInt()
{
    var first = new int[] { 1, 2, 3 };
    var second = new int[] { 2, 2, 2 };
    var expected = 1 * 2 + 2 * 2 + 3 * 2;
    var func = GetVectorMultiplyFunction<int>();
    var actual = func(first, second);
    Assert.AreEqual(expected, actual);
}
qyyhg6bp

qyyhg6bp1#

数组的长度不是类型定义的一部分,它是一个只能在运行时获得的值。
随着最近Generic Math的引入,您可以使用泛型进行乘法和加法运算,而无需构建表达式树;

public static T Calc<T>(T[] x, T[] y)
    where T : struct, IMultiplyOperators<T,T,T>, IAdditionOperators<T,T,T>
{
     T result = default(T);

     for(var i = 0; i < x.Length && i < y.Length; i++)
         result += x[i] * y[i];

     return result;
}

但是我假设对于您的任务,您需要构建一个与上述方法等效的表达式树,然后编译它。

jc3wubiy

jc3wubiy2#

这可能不是你想要的,但如果你只需要保留签名,这似乎可以解决你的问题:

public static Func<T[], T[], T> GetVectorMultiplyFunction<T>() where T : struct
{
     return (T[] x, T[] y) => {
     T result = default(T);      

     for(var i = 0; i < x.Length; i++)
     {
         var xd = (dynamic)x[i];
         var yd = (dynamic)y[i];
         result += (xd * yd);
     }
     
     return result;
};
afdcj2ne

afdcj2ne3#

代码中唯一需要表达式树的部分(假设您不能像其他两种解决方案那样使用通用数学或动力学)是运算符(加和乘)。
如果您单独编译运算符表达式,那么您就可以非常容易地使用LINQ,就像您最初的方法一样-类似于:

public static Func<T[], T[], T> GetVectorMultiplyFunction<T>() where T : struct
{
    static Func<T,T,T> GetOperatorFunction(Func<Expression, Expression, BinaryExpression> operatorExpression)
    {
        var x = Expression.Parameter(typeof(T));
        var y = Expression.Parameter(typeof(T));
        var body = operatorExpression(x, y);

        return Expression
            .Lambda<Func<T, T, T>>(body, x, y)
            .Compile();
    }

    var add = GetOperatorFunction(Expression.Add);
    var multiply = GetOperatorFunction(Expression.Multiply);

    return (xVector, yVector) =>
        xVector
            .Zip(yVector, multiply)
            .Aggregate(add);
}

相关问题