public static Dictionary<AST.Address, string> StoreOutputs(AST.Address[] outputs, DAG dag) { // output dict var d = new Dictionary<AST.Address, string>(); // partition all of the output addresses by their worksheet var addr_groups = outputs.GroupBy(addr => dag.getCOMRefForAddress(addr).WorksheetName); // for each worksheet, do an array read of the formulas foreach (IEnumerable<AST.Address> ws_fns in addr_groups) { // get worksheet used range var fstcr = dag.getCOMRefForAddress(ws_fns.First()); var rng = fstcr.Worksheet.UsedRange; // get used range dimensions var left = rng.Column; var right = rng.Columns.Count + left - 1; var top = rng.Row; var bottom = rng.Rows.Count + top - 1; // get names var wsname = new FSharpOption<string>(fstcr.WorksheetName); var wbname = new FSharpOption<string>(fstcr.WorkbookName); var path = fstcr.Path; // sometimes the used range is a range if (left != right || top != bottom) { // y is the first index // x is the second index object[,] data = rng.Value2; // fast array read var x_del = left - 1; var y_del = top - 1; foreach (AST.Address addr in ws_fns) { // construct address in formulas array var x = addr.X - x_del; var y = addr.Y - y_del; // get string String s = System.Convert.ToString(data[y, x]); if (String.IsNullOrWhiteSpace(s)) { d.Add(addr, ""); } else { d.Add(addr, s); } } } // and other times it is a single cell else { // construct the appropriate AST.Address AST.Address addr = AST.Address.NewFromR1C1(top, left, wsname, wbname, path); // make certain that it is actually a string String s = System.Convert.ToString(rng.Value2); // add to dictionary, as appropriate if (String.IsNullOrWhiteSpace(s)) { d.Add(addr, ""); } else { d.Add(addr, s); } } } return d; }