试图了解跨程序集的方法签名更改
Trying to understand method signature changes spanning assemblies
我们 运行 遇到了一个关于促销的 st运行ge 问题,我希望我能够用代码来解释它。我想了解为什么它会以现在的方式运行。
程序集 1
public static class Foo
{
public static string DoStuff()
{
// Do something
return "some string";
}
}
程序集 2:
public class Bar
{
public void SomeMethod()
{
// I realize the below is not what should be done for catching exceptions, as the exception is never thrown due to the return, and seems unnecessary either way...
// this is inherited code and has not been modified to correct.
try
{
var someValue = Foo.DoStuff();
}
catch (Exception)
{
return;
throw;
}
}
}
要求已更改,因此 DoStuff 需要接受一个参数,该参数的值会稍微改变行为。请注意,只有程序集 1.Foo 正在更改。
新富
public static class Foo
{
public static string DoStuff(bool someBool = false)
{
// Do something
return "some string";
}
}
这个重新编译很好,程序集 2 能够毫无怨言地成功使用更改后的方法签名。执行了我的签入,并提升了有更改的项目 dll(注意这只是 Assembly 1 dll)。
升级后我们发现程序集 2 在 Foo.DoStuff() 调用上失败了 - 不幸的是我无法提供异常,因为上面的代码吞没了它。
尽管程序集 2 中没有实际代码发生变化,但它似乎确实对重新编译时的 dll 产生了影响,尽管方法签名(至少在我看来)是相同的,因为为新参数。
我使用 dotnet peek 来查看 "old dll" 和 "new dlls"(即使没有对该程序集进行代码更改,并且确实注意到这两个 DLL 在旧版本中的区别DLL,没有提供默认值参数,但在重新编译时,提供了默认值参数。
我想我的问题可以归结为:
- 为什么程序集 2 上的编译代码会根据(至少我认为)应该是 t运行sparent 的方法签名而改变?
- 避免这种情况的方法是"deploy everything"吗?而不是尝试根据代码更改进行部署?请注意,DLL 未签入,因此程序集 2 没有实际的 "code change",尽管 DLL 根据对程序集 1 的更改而有所不同。
Why does the compiled code on assembly 2 change based on a method signature that (at least I think) should be transparent?
不,不应该。当您未指定与可选参数相对应的参数时,默认值将在调用站点提供 - 即您的情况下的程序集 2。这就是可选参数在 C# 中的工作方式。很痛苦,但这就是生活
Would the method of avoiding a situation like this just be "deploy everything"?
是的。基本上,程序集 2 中源代码的 含义 已更改,即使代码本身没有更改 - 因此编译后的代码已更改,需要重新部署。
您也可以在其他情况下看到像这样的细微突破性变化 - 相同的旧 "client" 代码可以针对新的 "receiving" 代码进行编译,但具有不同的含义。两个例子:
假设您将方法签名从 Foo(long x)
更改为 Foo(int x)
但在调用站点,您仅将其称为 Foo(5)
...两种情况,但代码不同。
假设您已将方法签名从 Foo(int x, int y)
更改为 Foo(int y, int x)
并且调用了 Foo(x: 5, y: 2)
... 同样,meaning 的代码从 Foo(5, 2)
变为 Foo(2, 5)
,如果你明白我的意思。针对新的 "receiving" 代码重新编译未更改的源代码将改变行为。
假设您在程序集 1 中有一个常量,例如public const string Foo = "Foo";
。如果将其更改为 public const string Foo = "Bar"
,但不使用 常量重新编译程序集 ,这些程序集仍将使用值 "Foo"。 (这也适用于可选参数的默认值。)
我们 运行 遇到了一个关于促销的 st运行ge 问题,我希望我能够用代码来解释它。我想了解为什么它会以现在的方式运行。
程序集 1
public static class Foo
{
public static string DoStuff()
{
// Do something
return "some string";
}
}
程序集 2:
public class Bar
{
public void SomeMethod()
{
// I realize the below is not what should be done for catching exceptions, as the exception is never thrown due to the return, and seems unnecessary either way...
// this is inherited code and has not been modified to correct.
try
{
var someValue = Foo.DoStuff();
}
catch (Exception)
{
return;
throw;
}
}
}
要求已更改,因此 DoStuff 需要接受一个参数,该参数的值会稍微改变行为。请注意,只有程序集 1.Foo 正在更改。
新富
public static class Foo
{
public static string DoStuff(bool someBool = false)
{
// Do something
return "some string";
}
}
这个重新编译很好,程序集 2 能够毫无怨言地成功使用更改后的方法签名。执行了我的签入,并提升了有更改的项目 dll(注意这只是 Assembly 1 dll)。
升级后我们发现程序集 2 在 Foo.DoStuff() 调用上失败了 - 不幸的是我无法提供异常,因为上面的代码吞没了它。
尽管程序集 2 中没有实际代码发生变化,但它似乎确实对重新编译时的 dll 产生了影响,尽管方法签名(至少在我看来)是相同的,因为为新参数。
我使用 dotnet peek 来查看 "old dll" 和 "new dlls"(即使没有对该程序集进行代码更改,并且确实注意到这两个 DLL 在旧版本中的区别DLL,没有提供默认值参数,但在重新编译时,提供了默认值参数。
我想我的问题可以归结为:
- 为什么程序集 2 上的编译代码会根据(至少我认为)应该是 t运行sparent 的方法签名而改变?
- 避免这种情况的方法是"deploy everything"吗?而不是尝试根据代码更改进行部署?请注意,DLL 未签入,因此程序集 2 没有实际的 "code change",尽管 DLL 根据对程序集 1 的更改而有所不同。
Why does the compiled code on assembly 2 change based on a method signature that (at least I think) should be transparent?
不,不应该。当您未指定与可选参数相对应的参数时,默认值将在调用站点提供 - 即您的情况下的程序集 2。这就是可选参数在 C# 中的工作方式。很痛苦,但这就是生活
Would the method of avoiding a situation like this just be "deploy everything"?
是的。基本上,程序集 2 中源代码的 含义 已更改,即使代码本身没有更改 - 因此编译后的代码已更改,需要重新部署。
您也可以在其他情况下看到像这样的细微突破性变化 - 相同的旧 "client" 代码可以针对新的 "receiving" 代码进行编译,但具有不同的含义。两个例子:
假设您将方法签名从
Foo(long x)
更改为Foo(int x)
但在调用站点,您仅将其称为Foo(5)
...两种情况,但代码不同。假设您已将方法签名从
Foo(int x, int y)
更改为Foo(int y, int x)
并且调用了Foo(x: 5, y: 2)
... 同样,meaning 的代码从Foo(5, 2)
变为Foo(2, 5)
,如果你明白我的意思。针对新的 "receiving" 代码重新编译未更改的源代码将改变行为。假设您在程序集 1 中有一个常量,例如
public const string Foo = "Foo";
。如果将其更改为public const string Foo = "Bar"
,但不使用 常量重新编译程序集 ,这些程序集仍将使用值 "Foo"。 (这也适用于可选参数的默认值。)