我想在c#中实现像编译器这样的范围变量知道变量在哪里定义。 我的意思是,像
int a = 5;
for (int i = 0; i < a; i++)
{
// Here you can use a variable after instantiating it, "a" can still be used
int b = 10;
}
// b cannot be used here.
我想用xml文件来做。像
<block>
<if>
<eq>
<makevar var='var1'>somevalue</makevar>
<makevar var='var2'>somevalue</makevar>
</eq>
</if>
<get var ='var1' />
</block>
此命令<get var='var1' />
无法使用,因为它不在其指定的范围内。
我该如何实现?
答案 0 :(得分:0)
问题有点模糊,但据我所知,你想在循环中为b分配一些东西,并希望能够在循环后读取它。对此的解决方案实际上非常简单:将变量b取出循环范围。
int a = 5;
int b = 0;
for (int i = 0; i < a; i++)
{
// Here you can use a and b, or declare a new variable only existing within this scope
b = 10;
}
// b is now usable everywhere within the class
答案 1 :(得分:0)
在遍历XML时,您可以跟踪范围变量。 'makevar'元素会将变量添加到直接父级的范围。我在你的例子中添加了评论以表明这个想法:
<block> <!-- block.scope="" -->
<if> <!-- if.scope=block.scope=="" -->
<eq> <!-- eq.scope=if.scope=="" -->
<!-- makevar.scope=eq.scope=="";eq.scope.add(var1) -->
<makevar var='var1'>somevalue</makevar>
<!-- makevar.scope=eq.scope=="var1";eq.scope.add(var2) -->
<makevar var='var2'>somevalue</makevar>
<get var ='var1'/> <!-- get.scope=eq.scope=="var1,var2" -->
</eq>
</if>
<get var ='var1'/> <!-- get.scope=block.scope=="" -->
</block>
通常在输入child时 - 将其范围设置为parent(不更改父范围)。当元素为makevar时 - 将此var添加到包含当前makevar的元素范围。
修改即可。更改上面的示例以更准确地显示想法。
答案 2 :(得分:0)
我知道我不应该,但我有空闲时间; - )
这是一个如何解决它的建议。它既不完整也没有真正优化或安全。它的目的是为您提供一些东西。您的问题是关于范围的,因此以下代码首先进行范围检查。
它是如何工作的?每个节点(元素)由一个为其提供特殊功能的类表示。每个节点但变量也是一个可以维护子块及其变量的块。在解析期间,通过搜索xml树来检查变量的范围,如果变量属于self或parent节点并且在self之前。
我已经优化了你的xml。
<强>程序强>:
class Program
{
static void Main(string[] args)
{
var xDoc = XDocument.Parse(xml);
var block = new Block(xDoc.Root);
}
// These lines will cause an exception because both variables are out of scope.
// <add arg1='a' arg2='b' />
// <add arg1='a' arg2='d' />
static string xml = @"
<block>
<var name='a'>2</var>
<if condition='true'>
<var name='b'>3</var>
</if>
<var name='c'>2</var>
<add arg1='a' arg2='a' />
<add arg1='a' arg2='b' />
<add arg1='a' arg2='c' />
<add arg1='a' arg2='d' />
<var name='d'>4</var>
</block>";
}
BlockBase
&amp;&amp;的 Block
强>:
// Provides common functionality for blocks.
abstract class BlockBase
{
protected BlockBase()
{
Variables = new List<Variable>();
Blocks = new List<BlockBase>();
}
protected BlockBase(XElement xBlock)
: this()
{
// Add variables and blocks.
foreach (var item in xBlock.Elements())
{
AddVariable(Variable.Parse(item));
AddBlock(IfStatement.Parse(item));
AddBlock(Addition.Parse(item));
}
}
BlockBase Parent { get; set; }
// Block variables.
public List<Variable> Variables { get; set; }
// Sub-blocks.
public List<BlockBase> Blocks { get; set; }
// Adds a variable.
private void AddVariable(Variable variable)
{
if (variable != null)
{
Variables.Add(variable);
}
}
// Adds a block.
private void AddBlock(BlockBase block)
{
if (block != null)
{
block.Parent = this;
Blocks.Add(block);
}
}
// Get a variable.
public Variable GetVariable(string name)
{
BlockBase block = this;
do
{
Variable variable = block.Variables.Where(x => x.Name == name).FirstOrDefault();
if (variable != null)
{
return variable;
}
block = block.Parent;
} while (block != null);
return null;
}
// Checks if variable is in scope.
protected bool IsInScope(XElement xElm, string varName)
{
// Traverses the tree and searches for variables in parent blocks and before self
// so that we don't get variables defined after self.
var xCurrentElm = xElm;
do
{
var variable =
xCurrentElm
.ElementsBeforeSelf()
.Where(x => x.Name.LocalName == "var" && x.Attribute("name").Value == varName)
.FirstOrDefault();
if (variable != null) return true;
xCurrentElm = xCurrentElm.Parent;
} while (xCurrentElm != null);
return false;
}
}
// Block class.
class Block : BlockBase
{
public Block(XElement xBlock)
: base(xBlock)
{
}
}
<强> IfStatement
强>:
// An if-statement.
class IfStatement : BlockBase
{
private IfStatement(XElement xIf)
: base(xIf)
{
Condition = xIf.Attribute("condition").Value;
}
public static IfStatement Parse(XElement xIf)
{
if (xIf.Name.LocalName != "if")
{
return null;
}
return new IfStatement(xIf);
}
public string Condition { get; set; }
// Evaluates the condition.
public bool Evaluate() { return bool.Parse(Condition); }
}
Addition
作为实际使用变量的内容:
// Addition block.
class Addition : BlockBase
{
private Addition(XElement xAddition)
{
Arg1 = xAddition.Attribute("arg1").Value;
Arg2 = xAddition.Attribute("arg2").Value;
if (!IsInScope(xAddition, Arg1))
{
throw new ArgumentOutOfRangeException("Arg1", String.Format("{0} is out of scope.", Arg1));
}
if (!IsInScope(xAddition, Arg2))
{
throw new ArgumentOutOfRangeException("Arg2", String.Format("{0} is out of scope.", Arg2));
}
}
public static Addition Parse(XElement xAddition)
{
if (xAddition.Name.LocalName != "add")
{
return null;
}
return new Addition(xAddition);
}
public string Arg1 { get; set; }
public string Arg2 { get; set; }
public int? Result { get; set; }
// Evaluates the addition.
public void Evaluate()
{
Variable arg1 = GetVariable(Arg1);
Variable arg2 = GetVariable(Arg2);
if (arg1 == null)
{
throw new ArgumentNullException("arg1");
}
if (arg2 == null)
{
throw new ArgumentNullException("arg2");
}
Result = int.Parse(arg1.Value) + int.Parse(arg2.Value);
}
}
<强> Variable
强>:
// Variable.
class Variable
{
private Variable(XElement xVariable)
{
Name = xVariable.Attribute("name").Value;
Value = xVariable.Value;
}
public static Variable Parse(XElement xVariable)
{
if (xVariable.Name.LocalName != "var")
{
return null;
}
return new Variable(xVariable);
}
public string Name { get; set; }
public string Value { get; set; }
}