【发布时间】:2011-03-31 20:11:31
【问题描述】:
更新:改进了解释,希望问题现在很清楚:)
大家好!
我有一个 XML,其中声明了 FSM 的转换(以及事件和状态偏离)。
这是 XML 的简化版本,它也会导致下面描述的问题:
<?xml version="1.0" encoding="UTF-8"?>
<FSM name="MediaPlayer">
<state name="FastForward"/>
<state name="PlayingMediaFile"/>
<transition name="FastForward to FastForward" source="FastForward" target="FastForward">
<trigger name="FastForwardButtonPressed" action="playingSpeed * 2" guard="currentMediaFile.CurrentPosition U+003C currentMediaFile.Lengtha"/>
</transition>
<transition name="FastForward to PlayingMediaFile" source="FastForward" target="PlayingMediaFile">
<trigger name="PlayButtonPressed" action="playingSpeed = 1" guard=""/>
</transition>
<event name="FastForwardButtonPressed"/>
<event name="PlayButtonPressed"/>
</FSM>
我的目标是使用 XSLT 在 C# 中生成 FSM。 FSM 的实现必须符合状态模式。因此,我需要为每个州创建一个类。在每个类中,方法将代表事件。由于这些类派生自一个包含所有方法(事件)的抽象类,因此每个类/状态都需要实现所有方法(事件)。当然并不是所有的方法都被实际实现,因为一个状态没有使用所有的事件。因此,我选择以异常方式实现未使用的事件。
为了生成 C# 代码,我需要遍历 XML 并为每个状态生成一个类。创建类后,下一步是为每个事件生成一个方法。目前,这是困难的部分。对于每个方法(事件),我需要检查我正在评估的当前状态是否存在事件。因此,我遍历 XML 并寻找属性“源”等于当前评估的状态/类的转换。如果找到一个,我检查触发子项是否与我正在评估的当前事件相同。如果两个测试都为真,则“transtion/trigger/@action”和“transtion/trigger/@guard”的内容需要用作当前方法/事件的实现。如果没有找到有效的转换,则表示该状态的事件不存在,因此必须作为异常实现。
目前我还没有编写用于读取动作和保护属性的代码,因此不会为此生成代码。现在,当转换对当前状态和事件有效时,我使用文本“实现保护/操作”,并使用文本“抛出新的 NotImplementedException();”当没有找到转换时。或者说,应该这样做……
我编写的代码几乎可以让我到达那里:
<xsl:for-each select="//state">
<xsl:variable name="currentStateName" select="@name"/>
public class <xsl:value-of select="@name"/> : <xsl:value-of select="$FsmName"/>States
{
public <xsl:value-of select="@name"/>()
{
Console.WriteLine("In <xsl:value-of select="@name"/>State");
}
<xsl:for-each select="//event">
public override void <xsl:value-of select="@name"/>(MediaPlayer player)
{
<xsl:variable name="currentEventName" select="@name"/>
<xsl:for-each select="//transition">
<xsl:if test="@source = $currentStateName">
<xsl:choose>
<xsl:when test="trigger/@name = $currentEventName">
implement guard/action
</xsl:when>
<xsl:otherwise>
throw new NotImplementedException();
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:for-each>
}
</xsl:for-each>
}
</xsl:for-each>
现在这段代码的输出是:
public class FastForward : MediaPlayerStates
{
public FastForward()
{
Console.WriteLine("In FastForwardState");
}
public override void FastForwardButtonPressed(MediaPlayer player)
{
implement guard/action
throw new NotImplementedException();
}
public override void PlayButtonPressed(MediaPlayer player)
{
throw new NotImplementedException();
implement guard/action
}
}
public class PlayingMediaFile : MediaPlayerStates
{
public PlayingMediaFile()
{
Console.WriteLine("In PlayingMediaFileState");
}
public override void FastForwardButtonPressed(MediaPlayer player)
{
}
public override void PlayButtonPressed(MediaPlayer player)
{
}
}
正如您可能理解的那样,这是错误的。在“FastForward”类中生成错误。它只需要“实现保护/动作”,而不需要“抛出新的 NotImplementedException();”。在“PlayingMediaFile”类中,没有生成任何内容,而需要用“throw new NotImplementedException();”填充因为那个类没有事件。
public class FastForward : MediaPlayerStates
{
public FastForward()
{
Console.WriteLine("In FastForwardState");
}
public override void FastForwardButtonPressed(MediaPlayer player)
{
implement guard/action
}
public override void PlayButtonPressed(MediaPlayer player)
{
implement guard/action
}
}
public class PlayingMediaFile : MediaPlayerStates
{
public PlayingMediaFile()
{
Console.WriteLine("In PlayingMediaFileState");
}
public override void FastForwardButtonPressed(MediaPlayer player)
{
throw new NotImplementedException();
}
public override void PlayButtonPressed(MediaPlayer player)
{
throw new NotImplementedException();
}
}
现在我明白为什么会出错了,我将尝试解释:当循环所有转换时,它会遇到两个转换。第一个将对测试进行评估,因此它会生成“实施警卫/操作”文本。现在它遍历到评估为假的第二个转换节点。由于错误评估,它会生成 NotImplementedException()。这发生在同一事件中,因此是错误的。
所以,据我所知,当测试为真时,for-each 循环的转换需要中断。如果没有找到匹配的转换,则需要生成“NotImplementedException”文本。
我尝试了各种方法,但我无法完成。有人可以帮帮我吗?
谢谢
【问题讨论】:
-
@r0h: 这一点我都不清楚。期望的输出是什么?
-
当被评估的状态和事件有相应的转换时,需要生成“实现保护/动作”。没有异常时需要生成异常。现在问题都是由于双重评估而产生的。这是因为有两个过渡节点。因此它需要在有有效测试时退出 for each 循环,并在没有有效测试时生成“实施保护/动作”或生成异常。
-
r0h:我认为您在这里有交叉引用,但您的问题使这一点不清楚。检查我的答案。
标签: c# xml xslt code-generation foreach