生成的输出中未调用发出的方法


我正在制作一个小型 DFA 编译器,它使用 System.Reflection.Emit 直接渲染到程序集

请注意,下面有一个 FALIB 定义。 当使用编译器时,它总是被定义。

我的 IL 代码应该实现这个的具体版本

#if FALIB
public
#endif
abstract partial class FARunner
{
		
	protected abstract int MatchImpl(LexContext lc);
	protected abstract FAMatch SearchImpl(LexContext lc);
	/// <summary>
	/// Searches through text for the next occurance of a pattern matchable by this machine
	/// </summary>
	/// <param name="lc">The <see cref="LexContext"/> with the text to search</param>
	/// <returns>A series of <see cref="FAMatch"/> instances with the matches</returns>
	public IEnumerable<FAMatch> Search(LexContext lc)
	{
		while(lc.Current!=LexContext.EndOfInput)
		{
			yield return SearchImpl(lc);
		}
	}
	/// <summary>
	/// Indicates whether this machine will match the indicated text
	/// </summary>
	/// <param name="lc">A <see cref="LexContext"/> containing the text</param>
	/// <returns>The accept symbol if matched, otherwise -1.</returns>
	public int Match(LexContext lc)
	{
		return MatchImpl(lc);
	}
	/// <summary>
	/// Searches through text for the next occurance of a pattern matchable by this machine
	/// </summary>
	/// <param name="@string">The <see cref="IEnumerable{char}"/> with the text to search</param>
	/// <returns>A series of <see cref="FAMatch"/> instances with the matches</returns>
	public IEnumerable<FAMatch> Search(IEnumerable<char> @string)
	{
		foreach (var match in Search(LexContext.Create(@string)))
		{
			yield return match;
		}
	}
	/// <summary>
	/// Searches through text for the next occurance of a pattern matchable by this machine
	/// </summary>
	/// <param name="reader">The <see cref="TextReader"/> with the text to search</param>
	/// <returns>A series of <see cref="FAMatch"/> instances with the matches</returns>
	public IEnumerable<FAMatch> Search(TextReader reader)
	{
		foreach (var match in Search(LexContext.CreateFrom(reader)))
		{
			yield return match;
		}
	}
	/// <summary>
	/// Indicates whether this machine will match the indicated text
	/// </summary>
	/// <param name="text">The text</param>
	/// <returns>True if the passed in text was a match, otherwise false.</returns>
	public int Match(IEnumerable<char> text)
	{
		return Match(LexContext.Create(text));
	}

}

它只需要用具体方法填充 SearchImpl 和 MatchImpl ,我已经完成了,尽管它们目前抛出未实现的错误。

我遇到的麻烦是这个 – MatchImpl 方法调用得很好。

SearchImpl 方法——这很奇怪。 它不仅不会被调用,而且委托给它的任何方法也不会被调用。 我没有收到错误、编译器抛出或运行时错误。 当我尝试调用它时,它只是默默地失败了。

我唯一能想到的是我的返回类型是一个结构。 这是我能看到的唯一区别——好吧,还有名字。

我尝试过的:

C#
public static partial class FACompiler
{
	public static FARunner Compile(this FA fa, IProgress<int> progress = null)
	{
		if (fa == null) throw new ArgumentNullException(nameof(fa));
		fa = fa.ToDfa(progress);
		var name = "FARunner" + fa.GetHashCode();
		var asmName = new AssemblyName(name);
		var asm = Thread.GetDomain().DefineDynamicAssembly(asmName, AssemblyBuilderAccess.Run);
		ModuleBuilder mod = asm.DefineDynamicModule("M"+name);
		TypeBuilder type = mod.DefineType(name, TypeAttributes.Public | TypeAttributes.Sealed, typeof(FARunner));
		Type[] paramTypes = new Type[] { typeof(LexContext) };
		Type searchReturnType = typeof(FAMatch);
		MethodBuilder searchImpl = type.DefineMethod("SearchImpl", MethodAttributes.Public | MethodAttributes.ReuseSlot |
			MethodAttributes.Virtual | MethodAttributes.HideBySig, searchReturnType, paramTypes);
		ILGenerator searchGen = searchImpl.GetILGenerator();
		searchGen.ThrowException(typeof(NotImplementedException));
			
		MethodInfo searchImplBase = typeof(FARunner).GetMethod("SearchImpl",BindingFlags.NonPublic | BindingFlags.Instance);
		type.DefineMethodOverride(searchImpl, searchImplBase);

		Type matchReturnType = typeof(int);
		MethodBuilder match = type.DefineMethod("MatchImpl", MethodAttributes.Public | MethodAttributes.ReuseSlot |
			MethodAttributes.Virtual | MethodAttributes.HideBySig, matchReturnType, paramTypes);
		ILGenerator matchGen = match.GetILGenerator();
		matchGen.ThrowException(typeof(NotImplementedException));
		MethodInfo matchBase = typeof(FARunner).GetMethod("MatchImpl", BindingFlags.NonPublic | BindingFlags.Instance);
		type.DefineMethodOverride(match, matchBase);

		Type newType = type.CreateType();

		return (FARunner)Activator.CreateInstance(newType);

	}
}

我还尝试添加这些行来调整堆栈,以防万一即使在抛出异常时也需要填充堆栈:

C#
LocalBuilder famatch = searchGen.DeclareLocal(typeof(FAMatch));
searchGen.Emit(OpCodes.Ldloca_S, famatch);
searchGen.Emit(OpCodes.Initobj, typeof(FAMatch));

我得到相同的结果。

解决方案1

我不明白为什么,但是当我从 FARunner 类中取出收益并手动实现我的枚举器时,一切都工作正常。

尽管我很困惑,但我还是把这个问题解决了。

コメント

タイトルとURLをコピーしました