代写 Using System;

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 GetNamesOfAllNonemptyCells();

///

/// 如果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 SetCellContents(String name, double number);

///

/// 如果text是null,抛出一个ArgumentNullException

/// 否则,如果name是一个null或者不合理的,抛出一个InvalidNameException。

/// 否则,指定单元格的内容将变为文本(text)。该方法返回一个由名称加上所有其他单元格的名称的集合,这些单元格的值直接或间接地取决于指定的单元格。
///例如,如果name为A1,B1包含A1 * 2,C1包含B1 + A1,则返回(return)集合{A1,B1,C1}。

///

public abstract ISet SetCellContents(String name, String text);

///

/// 要求在formula里面的所有变量都是合理的单元格名。

/// 如果name是null或者不合理的,抛出一个InvalidNameException。

/// 否则,如果将指定单元格的内容更改为公式将导致一个循环依赖,抛出一个CircularException

/// 否则,指定单元格的内容将变为公式(formula)。该方法返回(return)一个由名称(name)加上所有其他单元格的名称(name)组成的Set,这些单元格的值直接或间接地取决于指定的单元格。
///例如,如果name为A1,B1包含A1 * 2,C1包含B1 + A1,则返回集合{A1,B1,C1}。

///

public abstract ISet SetCellContents(String name, Formula formula);

///

/// 如果name是一个null,抛出一个ArgumentNullException.

/// 否则,如果name不是一个合理的单元格name,那么抛出一个InvalidNameException.

/// 否则,返回一个枚举,没有重复,所有单元格的名称
值直接取决于指定单元格的值。换句话说,回报
包含所有单元格名称的枚举,没有重复
公式包含名称。

例如,假设 A1包含3,B1包含公式A1*A1, C1包含公式B1+A1,D1包含公式B1-C1.A1的直接从属单元格是B1和C1。

///

protected abstract IEnumerable GetDirectDependents(String name);

///

/// 不需要更改此处。如需要解释,可以联系买家。

///

protected IEnumerable GetCellsToRecalculate(ISet names)

{

LinkedList changed = new LinkedList();

HashSet visited = new HashSet();

foreach (String name in names)

{

if (!visited.Contains(name))

{

Visit(name, name, visited, changed);

}

}

return changed;

}

///

///使用单组名称调用其他版本的GetCellsToRecalculate的便捷方法。有关详细信息,请参阅其他版本

///

protected IEnumerable GetCellsToRecalculate(String name)

{

return GetCellsToRecalculate(new HashSet() { name });

}

///

/// A helper for the GetCellsToRecalculate method.

///

private void Visit(String start, String name, ISet visited, LinkedList modified)

{

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);

}

}

}