保存说明以供以后评估,可能吗?

时间:2018-03-05 16:07:56

标签: c# lazy-evaluation evaluation delayed-execution

我想保存"说明"如何在以后确定值,而不是在当前时间保存实际值。 这甚至可能吗?

一个简单的C#示例:

int[] myArray = new int[2];
Dictionary<string, int> myDictionary = new Dictionary<string, int>();
//dictionary type can be changed if required

myArray[0] = 1;
myArray[1] = 2;

myDictionary.Add("total", (myArray[0] + myArray[1]) ); // Don't evaluate the value now

myArray[0] = 3;
myArray[1] = 4;

Console.WriteLine("total 2 = " + myDictionary["total"]); // Evaluate the value now
//Desired output: 7 (3+4), actual output = 3 (1+2)

2 个答案:

答案 0 :(得分:1)

您可以使用(expression bodied read-only) properties

public int[] MyArray { get; set; }

public string CurrentResult => $"total: {MyArray.Sum()} ({string.Join("+", MyArray)})";

如果您需要本地变量,可以使用local functions

string GetCurrentResult() => $"total: {MyArray.Sum()} ({string.Join("+", MyArray)})";

MyArray[0] = 1;
MyArray[1] = 2;
Console.WriteLine(GetCurrentResult()); // total: 3 (1+2)
MyArray[0] = 3;
MyArray[1] = 4;
Console.WriteLine(GetCurrentResult()); // total: 7 (3+4)

如果您不使用C#7,可以使用Func<string>代理:

Func<string> GetCurrentResult = () => $"total: {MyArray.Sum()} ({string.Join("+", MyArray)})";

答案 1 :(得分:1)

您正在寻找Lazy<T>。在通过Func<T>属性访问它之前,它不需要评估Value。评估完成后,将存储结果以供进一步访问。因此,您的代码可能类似于:

int[] myArray = new int[2];

var total = new Lazy<int>(() => myArray.Sum());
myArray[0] = 1;
myArray[1] = 2;
myArray[0] = 3;
myArray[1] = 4;

Console.WriteLine("total = " + total);
Console.WriteLine("total = " + total.Value);
Console.WriteLine("total = " + total);

此代码的输出为:

total = Value is not created.
total = 7
total = 7

请注意,在不调用total.Value的情况下,结果不是int,而是告诉我们表达式尚未被评估的消息。调用total.Value后,对total的后续访问会产生值(由于ToString()中的隐式Console.WriteLine()调用)。

使用Lazy<T>的好处是值是持久的,而不是每次访问时都重新计算。这使得它非常适合每次使用类时可能无法访问的类中的属性/字段,但需要很长时间才能生成值。

编辑:基于Op的反馈Lazy<T>并不完全是他们想要的。

如果您总是希望每次访问时都要评估表达式,那么您需要一个方法或Func<T>。所以想象你有这样一个类:

public class MyClass
{
    public int[] Vals {get;set;}
}

如果您想定义获取Vals总和(例如)的自定义方式,您可以选择几个简单的选项。

一种类方法

public class MyClass
{
    public int[] Vals {get;set;}
    public int SumOfVals()
    {
        return Vals.Sum();
    }
}

如果你选择类方法,你可以(可以想象)使类通用(MyClass<T>)并使用虚拟/抽象方法来实现具体的SumOfVals方法。

在类

中实现的Func<T>
public class MyClass
{
    public int[] Vals {get;set;}
    public Func<int[], int> SumOfVals { get;set; }
}

现在,每次实例化类时,都可以将SumOfVals设置为某个自定义函数。如果你没有把它设置为任何东西,如果你试图对它做任何事情,你将得到一个NullReferenceException。

A Func<T>内联实施

var vals = new int[2];
var sumVals = new Func<int[], int>((arr) => arr.Sum());
Console.WriteLine(sumVals(vals));

这可能是最灵活的,但这可能导致一些意大利面条代码。我建议只在类中调用MyClass或在MyClass中创建方法来处理此逻辑。