开发者

Can I set a Func<> function with runtime variables to omit passing them as parameters in C#?

开发者 https://www.devze.com 2022-12-14 15:48 出处:网络
I have a numeric开发者_运维问答al analysis program which for simplicity calculates an algorithm similar to:

I have a numeric开发者_运维问答al analysis program which for simplicity calculates an algorithm similar to:

y = ax^3 + bx^2 + cx + d;

I calculate the values of a,b,c,d at runtime and would like to pass the following equivalent as a Func<double, double>. Where I can set a value for X, and get Y.

y = 12x^3 + 13x^2 + 14x + 15; 

Where 12,13,14,15 are the numbers calculated at runtime.

I realise this can be done by passing in a double array, like so: Func<double[], double> but I am trying to avoid passing around the constants (which can be many).

Is there any way to set these numbers in a func at runtime?

(Preferably without making the calculation of a,b,c,d part of the Func<> itself? The calculation of a,b,c,d is 80% of the work)

E.g.:

a = ...

b = ...

c = ...

Func<x, double> {
     ((const)a) * x^3 +   ((const)b) * x^2 +   ((const)c) * x + 15;
}`

For every evaluation of ABCD - I will evaluate 10 x's.


I'm not sure if I understand quite what you are asking, but you could try something like this, perhaps?

Func<double, double> CreateCalculationFunc()
{
    double a = heavy calculation;
    double b = heavy calculation;
    double c = heavy calculation;
    double d = heavy calculation;

    Func<double, double> calculation = (x) =>
    {
        // You can use the constants in here without passing them as parameters
        return x * (a * b / c - d);
    };

    return calculation;
}

In this case, you can just make a call to the CreateCalculationFunc(), which will do the heavy calculations once, and return a reusable Func<double,double> for doing your variable calculations.

Of course, this is extensible to any amount of pre-calculated constants and more than one variable.


Can't you create a class that contains your calculation (Func<double,double>) method that has properties for your "constants". Then you set the properties and use a reference to the Calculate method as your Func<double,double> delegate:

public class Calculator
{
    public double A { get; set; };
    public double B { get; set; };
    public double C { get; set; };
    public double D { get; set; };

    public double Calculate(double x)
    {
        return A*x*x*x + B*x*x + C*x + D;
    }
}


This sounds like you'd want what the functional languages call "currying" or "partial application".

Given a Func<a, b, c, d, x, result> you'd apply the values one by one and reduce the parameter set.

Func<a, b, c, d, x, result>(valueOfA)

would result in a function with the signature

Func<b, c, d, x, result>

which you can pass on.

Relevant links for currying/partial application in C#:

  • http://blogs.msdn.com/wesdyer/archive/2007/01/29/currying-and-partial-function-application.aspx
  • http://blogs.msdn.com/sriram/archive/2005/08/07/448722.aspx
  • http://www.c-sharpcorner.com/UploadFile/rmcochran/Curry01122008102239AM/Curry.aspx

Or - give F# a try ;)

Edit: A short code sample, created from the reference sites above:

Boilerplate code:

    public static Func<B, R> Partial<A, B, R>(this Func<A, B, R> f, A a) {
        return b => f(a, b);
    }

    public static Func<B, C, R> Partial<A, B, C, R>(this Func<A, B, C, R> f, A a) {
        return (b, c) => f(a, b, c);
    }

    public static Func<B, C, D, R> Partial<A, B, C, D, R>(this Func<A, B, C, D, R> f, A a) {
        return (b, c, d) => f(a, b, c, d);
    }

Your Code:

Func<double, double, double, double, double> yourCalculation = (a, b, c, x) => a*Math.Pow(x, 3) + b*Math.Pow(x, 2) + c*x;

var aDefined = yourCalculation.Partial(12);
var bDefined = aDefined.Partial(13);
var cDefined = bDefined.Partial(14);

cDefined is now a new Func that "knows" the preapplied values and can be passed around as you like. I couldn't find a readymade solution for delegates with more than 4 parameters (i.e. things that don't fit a Func<...>), but that should be possible as well.

This way you're precalculating once and just the way you do it today, but you can narrow down the function to the last part for every consumer.


There are several different Func<> overloads, you can use one with 5 generic parameters, with the first one being a KeyValuePair:

Func<KeyValuePair<double,double>,double,double,double,double>

So you pass a and b as the kvp and c,d and x as the other parameters.


In hindsight I could actually just do this;

Class {
    a = ...
    b = ...

    Func Algorithm = (x) => {
        return x*a + x*b;
    }

    return Algorithm;
}

But was just a little confused by Func<> and Action<> as it was my first time using them! Thanks for your help.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号