编译器如何知道范围变量

时间:2015-01-08 08:00:49

标签: c# variables scope

我想在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' />无法使用,因为它不在其指定的范围内。

我该如何实现?

3 个答案:

答案 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; }
}