Using System;
using System.Collections.Generic;
using Formulas;
namespace SS
{
///
/// 抛出以指示对单元格的更改将导致循环依赖。
///
public class CircularException : Exception
{
}
///
///抛出以指示name参数为null或无效。
///
public class InvalidNameException : Exception
{
}
///
/// 单元格的可能值
///
public struct FormulaError
{
///
/// 构造一个包含解释性原因的FormulaError。
///
public FormulaError(String reason)
: this()
{
Reason = reason;
}
///
/// The reason why this FormulaError was created. 创建此FormulaError的原因。
///
public string Reason { get; private set; }
}
///
/// AbstractSpreadsheet对象(object表示简单电子表格的状态。电子表格由无数个命名单元格组成。
/// 字符串(string)s是一个有效的单元名称,当且仅当它包含一个或多个字母,后跟非零数字,后跟零个或多个数字
///例如,“A15”,“a15”,“XY32”和“BC7”是有效的单元名称。另一方面,“Z”,“X07”和“hello”不是有效的单元名称。
/// 电子表格包含与每个可能的单元名称对应的唯一单元格。
/// 除了名称,每个单元格都有一个内容和一个值。区别很重要,在编写代码,撰写评论和提问时,理解区别并使用正确的术语非常重要。
/// 单元格的内容可以是(1)一个字符串(string),(2)一个double,或(3)一个公式(formula)。如果内容是空字符串,我们说该单元格为空。 (通过类比,Excel中单元格的内容是选择单元格时在编辑行上显示的内容。)
/// 在空的电子表格中,每个单元格的内容都是空字符串。
/// 单元格的值可以是(1)一个字符串(string),(2)一个double,或(3)一个FormulaError。 (通过类比,Excel单元格的值是该单元格在网格中的位置。)
/// 如果单元格的内容是字符串(string),则其值为该字符串(string)。
/// 如果单元格的内容是double,则其值为该double。
/// 如果单元格的内容是Formula,则其值可以为一个double或者一个FormulaError。
/// 当然,公式(Formula)的值可以取决于变量的值。公式变量的值是它命名的电子表格单元格的值(如果该单元格的值
value是double)或未定义(否则)。如果公式取决于未定义的变量或除以零,则其值为FormulaError。否则,其值为double,如Formula.Evaluate中所指定。
/// 永远不允许电子表格包含建立循环依赖关系的公式组合。当单元依赖于自身时,存在循环依赖。
///例如,假设A1包含B1 * 2,B1包含C1 * 2,C1包含A1 * 2。
/// A1取决于B1,它取决于C1,它取决于A1。那是循环依赖。
///
public abstract class AbstractSpreadsheet
{
///
/// Enumerates the names of all the non-empty cells in the spreadsheet.
///
public abstract IEnumerable
///
/// 如果name为null或invalid,则抛出InvalidNameException、
否则,返回指定单元格的内容(而不是值)。返回值应该是string,double或Formula。
///
public abstract object GetCellContents(String name);
///
/// 如果name为null或invalid,则抛出InvalidNameException
/// 否则,指定单元格的内容将变为数字。该方法返回一个由名称加上所有其他单元格的名称的集合,这些单元格的值直接或间接地取决于指定的单元格。
/// 例如,如果name为A1,B1包含A1 * 2,C1包含B1 + A1,则返回集合{A1,B1,C1}。
///
public abstract ISet
///
/// 如果text是null,抛出一个ArgumentNullException
/// 否则,如果name是一个null或者不合理的,抛出一个InvalidNameException。
/// 否则,指定单元格的内容将变为文本(text)。该方法返回一个由名称加上所有其他单元格的名称的集合,这些单元格的值直接或间接地取决于指定的单元格。
///例如,如果name为A1,B1包含A1 * 2,C1包含B1 + A1,则返回(return)集合{A1,B1,C1}。
///
public abstract ISet
///
/// 要求在formula里面的所有变量都是合理的单元格名。
/// 如果name是null或者不合理的,抛出一个InvalidNameException。
/// 否则,如果将指定单元格的内容更改为公式将导致一个循环依赖,抛出一个CircularException
/// 否则,指定单元格的内容将变为公式(formula)。该方法返回(return)一个由名称(name)加上所有其他单元格的名称(name)组成的Set,这些单元格的值直接或间接地取决于指定的单元格。
///例如,如果name为A1,B1包含A1 * 2,C1包含B1 + A1,则返回集合{A1,B1,C1}。
///
public abstract ISet
///
/// 如果name是一个null,抛出一个ArgumentNullException.
/// 否则,如果name不是一个合理的单元格name,那么抛出一个InvalidNameException.
/// 否则,返回一个枚举,没有重复,所有单元格的名称
值直接取决于指定单元格的值。换句话说,回报
包含所有单元格名称的枚举,没有重复
公式包含名称。
例如,假设 A1包含3,B1包含公式A1*A1, C1包含公式B1+A1,D1包含公式B1-C1.A1的直接从属单元格是B1和C1。
///
protected abstract IEnumerable
///
/// 不需要更改此处。如需要解释,可以联系买家。
///
protected IEnumerable
{
LinkedList
HashSet
foreach (String name in names)
{
if (!visited.Contains(name))
{
Visit(name, name, visited, changed);
}
}
return changed;
}
///
///使用单组名称调用其他版本的GetCellsToRecalculate的便捷方法。有关详细信息,请参阅其他版本
///
protected IEnumerable
{
return GetCellsToRecalculate(new HashSet
}
///
/// A helper for the GetCellsToRecalculate method.
///
private void Visit(String start, String name, ISet
{
visited.Add(name);
foreach (String n in GetDirectDependents(name))
{
if (n.Equals(start))
{
throw new CircularException();
}
else if (!visited.Contains(n))
{
Visit(start, n, visited, modified);
}
}
modified.AddFirst(name);
}
}
}