添加可选参数后出现System.MissingMethodException异常

40

我在一个组件中使用了可选参数,但是调用它的另一个组件没有更新参数数量就进行了编译。只有添加了参数的那个组件才被编译和部署为修补程序,而调用的那个组件保持不变。

当调用组件运行时,它会出现错误:

异常信息

异常类型:System.MissingMethodException 消息:"未找到方法:'LabelURLs IPSD.BnB.Transaction.Postage.GetLabelURLs(System.String)'。" 数据:System.Collections.ListDictionaryInternal TargetSite: Void GenerateScanForm(Int32, Int32) HelpLink: NULL Source: BnBDispenseQueueProcess

据我所知,由于新的参数是可选的,它不应该引发错误。还有一件事,调用组件(EXE)作为Windows服务运行。

我们发现了一个非常奇怪的解决方法来使它运行。首先删除更改后的组件,然后运行调用组件,此时会报告DLL未找到。然后再放回相同的DLL文件,调用组件就能正常工作 :)

我想我可能缺少.NET内部的某些知识。

如果需要更多信息,请告诉我。


我们在一个常用库中添加了可选参数。这破坏了所有正在运行的模块(幸运的是,它是在测试环境中)。这些都是 .net 的高级开发功能,看来我们在使用它之前必须深入了解它们。感谢您的提问。 - CreativeManix
@CreativeManix,请告诉我你的发现。我无法完全理解为什么它会表现出这样的行为,可能是一些编译技巧在幕后发生了。 - sandeep
正如Jon Skeet所提到的,可选参数是编译时特性。在调用程序集的编译时,可选参数值将传递默认值。因此,如果您向公共库添加了可选参数,请确保同时编译调用程序集。如果您不想编译所有调用程序集,最好不要使用可选参数,而是使用重载方法代替; - CreativeManix
@CreativeManix 谢谢分享信息 :) - sandeep
1个回答

58

只有添加了参数的组件被构建并作为补丁部署了。调用组件是旧的,因为其中没有任何更改。

实际上它应该有所更改,因为旧代码调用了一个不存在的方法!

据我所知,由于新参数是可选的,所以不应引发错误。

这不是执行时决定 - 而是在编译时决定。如果您有这样的方法:

void Foo(int x, int y = 5)

然后你可以这样调用:

Foo(10);

然后编译器将其有效地转换为以下调用:

Foo(10, 5);

这个调用在二进制文件中具有完整的参数列表。如果你想以不影响二进制兼容性的方式从单参数版本切换到多参数版本,你需要添加一个重载函数,例如:

void Foo(int x)
{
    Foo(x, 5);
}

void Foo(int x, int y)
{
    ...
}

或者,您也可以重建调用代码并重新部署。

我对您的解决方法深表怀疑。您确定在将DLL放回原位时,替换的是新版本(带有可选参数),而不是旧版本吗?


是的,我只替换为新版本。你的回答很有道理。但由于解决方法,它在我的情况下并不完全正确。 - sandeep
@sandeep:我强烈怀疑你对解决方法的诊断有误。你试过多少次了?你确定已经使用了新代码吗?你确定没有替换调用代码吗?这根本不应该起作用——除非你使用动态类型,否则C#中没有任何机制可以实现这一点。 - Jon Skeet
@sandeep:抱歉,我不明白你之前的评论是什么意思。 - Jon Skeet
@sandeep:不,它真的不应该这样。如果您仍然有不匹配的二进制文件,它真的,真的不应该工作。您确定用“旧”的二进制文件替换了它而不是重新编译的吗? - Jon Skeet
1
@sandeep:是的,这会有很大的影响。虽然它没有解释解决方法,但它使其他所有内容都变得不那么重要了。当你提问时,你真的需要考虑到这样重要的信息。请发布你用来调用该方法的代码。 - Jon Skeet
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接