C# 试图理解跨越程序集的方法签名更改

C# 试图理解跨越程序集的方法签名更改,c#,.net,dll,dependencies,.net-assembly,C#,.net,Dll,Dependencies,.net Assembly,我们在促销时遇到了一个奇怪的问题,我希望我能用代码来解释它。我想了解它为什么会这样做 大会1 public static class Foo { public static string DoStuff() { // Do something return "some string"; } } 大会2: public class Bar { public void SomeMethod() { // I

我们在促销时遇到了一个奇怪的问题,我希望我能用代码来解释它。我想了解它为什么会这样做

大会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(注意,这只是程序集1 dll)

升级后,我们发现程序集2在Foo.DoStuff()调用上失败-不幸的是,我无法提供异常,因为上面的代码正在吞噬它

尽管汇编2中没有实际的代码更改,但它似乎确实在重新编译时对dll产生了影响,即使方法签名(至少在我看来)是相同的,因为为新参数提供了默认值

我使用dotnet peek查看“旧dll”和“新dll”(尽管该程序集没有代码更改,并且确实注意到两个dll中的差异,即在旧dll中,没有提供默认值参数,但在重新编译中,提供了默认值参数

我想我的问题可以归结为:

  • 为什么汇编2上的编译代码会基于(至少我认为)应该是透明的方法签名进行更改
  • 避免这种情况的方法是否只是“部署所有内容”?而不是尝试根据代码更改进行部署?请注意,DLL没有签入,因此程序集2没有实际的“代码更改”,尽管DLL根据程序集1的更改而有所不同
  • 为什么汇编2上的编译代码会基于(至少我认为)应该是透明的方法签名进行更改

    不,不应该。当您不指定与可选参数对应的参数时,默认值将在调用站点提供—在您的情况下是assembly 2。这就是可选参数在C#中的工作方式。这是一种痛苦,但这就是生活

    避免这种情况的方法是否就是“部署一切”

    是的。基本上,程序集2中源代码的含义已经改变,即使代码本身没有改变——因此编译后的代码已经改变,需要重新部署

    在其他情况下,您也可以看到类似这样的细微变化-相同的旧“客户端”代码与新的“接收”代码进行编译,但含义不同。两个示例:

    • 假设您将方法签名从
      Foo(long x)
      更改为
      Foo(int x)
      ,但在调用站点,您仅将其称为
      Foo(5)
      …它在两种情况下都编译,但编译为不同的代码

    • 假设您将一个方法签名从
      Foo(intx,inty)
      更改为
      Foo(inty,intx)
      ,并调用
      Foo(x:5,y:2)
      …再次,代码的含义从
      Foo(5,2)
      更改为
      Foo(2,5)
      ,如果您明白我的意思的话。根据新代码重新编译未更改的源代码“接收”代码将改变行为

    • 假设程序集1中有一个常量,例如
      public const string Foo=“Foo”
      。如果将其更改为
      public const string Foo=“Bar”
      ,但不使用该常量重新编译程序集,则这些程序集仍将使用“Foo”值(这也适用于可选参数的默认值)

    为什么汇编2上的编译代码会基于(至少我认为)应该是透明的方法签名进行更改

    不,不应该。当您不指定与可选参数对应的参数时,默认值将在调用站点提供—在您的情况下是assembly 2。这就是可选参数在C#中的工作方式。这是一种痛苦,但这就是生活

    避免这种情况的方法是否就是“部署一切”

    是的。基本上,程序集2中源代码的含义已经改变,即使代码本身没有改变——因此编译后的代码已经改变,需要重新部署

    在其他情况下,您也可以看到类似这样的细微变化-相同的旧“客户端”代码与新的“接收”代码进行编译,但含义不同。两个示例:

    • 假设您将方法签名从
      Foo(long x)
      更改为
      Foo(int x)
      ,但在调用站点,您仅将其称为
      Foo(5)
      …它在两种情况下都编译,但编译为不同的代码

    • 假设您将方法签名从
      Foo(intx,inty)
      更改为
      Foo(inty,intx)
      ,并调用
      Foo(x:5,y:2)
      …再次,代码的含义从
      Foo(5,2)
      更改为
      Foo(2,5)
      ,如果您明白我的意思的话。根据新的接收“代码”将改变行为

    • 假设程序集1中有一个常量,例如
      public const string Foo=“Foo”
      。如果将其更改为
      public const string Foo=“Bar”
      ,但不使用该常量重新编译程序集,则这些程序集仍将使用“Foo”值(这也适用于可选参数的默认值)

    为什么汇编2上的编译代码会基于(至少我认为)应该是透明的方法签名进行更改

    不,不应该。当您不指定与可选参数对应的参数时,默认值将在调用站点提供—在您的情况下是assembly 2。这就是可选参数在C#中的工作方式。这是一种痛苦,但这就是生活

    避免这种情况的方法是否就是“部署一切”