试图了解跨越程序集的方法签名更改 [英] Trying to understand method signature changes spanning assemblies

查看:29
本文介绍了试图了解跨越程序集的方法签名更改的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们在促销时遇到了一个奇怪的问题,我希望我能用代码来解释它.我想了解为什么它的行为方式如此.

We ran into a strange problem with a promotion and I'm hoping I'll be able to explain it with code. I want to understand why it behaves in the manner it is.

组装 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 发生了变化.

Requirements changed so that DoStuff would need to take in a parameter, the value of which would change the behavior slightly. Note that only assembly 1.Foo is changing.

新福

public static class Foo
{
    public static string DoStuff(bool someBool = false)
    {
        // Do something

        return "some string";
    }
}

这重新编译得很好,并且程序集 2 能够成功地使用更改后的方法签名而没有任何抱怨.执行了我的签入,并提升了已更改的项目 dll(请注意,这只是 Assembly 1 dll).

This recompiled fine, and Assembly 2 was able to successfully utilize the changed method signature without complaint. My check in was performed, and project dlls that had changes were promoted (note this was only Assembly 1 dll).

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

After promotion we found out that Assembly 2 was failing on the Foo.DoStuff() call - unfortunately I cannot provide an exception as the above code was swallowing it.

即使在程序集 2 中没有更改实际代码,它似乎确实对重新编译时的 dll 产生了影响,即使方法签名 - 至少在我看来 - 由于为新提供了默认值而相同参数.

Even though no actual code changed in Assembly 2, it did seem to have an impact on the dll on recompile, even though the method signature - at least in my mind - is the same due to providing a default value for the new parameter.

我使用 dotnet peek 来查看旧 dll"和新 dll"(即使该程序集没有代码更改,并且确实注意到旧 DLL 中的两个 DLL 的差异,默认情况下)没有提供value参数,但是在重新编译的时候,提供了默认的value参数.

I used dotnet peek in order to peek at the "old dll" and the "new dlls" (even though no code change to that assembly and did note a difference in the two DLLs in that in the old DLL, the default value parameter was not supplied, but in the recompiled, the default value parameter was supplied.

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

I guess my question(s) boil down to this:

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

推荐答案

为什么程序集 2 上的编译代码会根据(至少我认为)应该是透明的方法签名进行更改?

Why does the compiled code on assembly 2 change based on a method signature that (at least I think) should be transparent?

不,不应该.当您没有指定与可选参数对应的参数时,调用站点会提供默认值 - 即您的情况下的程序集 2.这就是可选参数在 C# 中的工作方式.这是一种痛苦,但这就是生活.

No, it shouldn't. When you don't specify an argument to correspond with an optional parameter, the default value is provided at the call site - i.e. assembly 2 in your case. That's how optional parameters work in C#. It's a pain, but that's life.

避免这种情况的方法只是部署一切"吗?

Would the method of avoiding a situation like this just be "deploy everything"?

是的.基本上,程序集 2 中源代码的含义发生了变化,即使代码本身没有变化 - 因此编译后的代码发生了变化,需要重新部署.

Yes. Basically, the meaning of the source in assembly 2 has changed even though the code itself hasn't - so the compiled code has changed, and it needs to be redeployed.

在其他情况下,您也可以看到类似这样的细微的重大变化 - 相同的旧客户端"代码针对新的接收"代码进行编译,但具有不同的含义.两个例子:

You can see subtle breaking changes like this in other cases, too - where the same old "client" code compiles against new "receiving" code, but has a different meaning. Two examples:

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

  • Suppose you change a method signature from Foo(long x) to Foo(int x) but at the call site, you only call it as Foo(5)... that compiles in both cases, but to different code.

假设您将方法签名从 Foo(int x, int y) 更改为 Foo(int y, int x) 并且您有一个调用Foo(x: 5, y: 2)... 再次,代码的含义Foo(5, 2)改变了到 Foo(2, 5),如果你明白我的意思.针对新的接收"代码重新编译未更改的源代码将改变行为.

Suppose you have change a method signature from Foo(int x, int y) to Foo(int y, int x) and you have a call of Foo(x: 5, y: 2)... again, the meaning of the code changes from Foo(5, 2) to Foo(2, 5), if you see what I mean. Recompiling the unchanged source code against the new "receiving" code will change the behaviour.

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

Suppose you have a constant in assembly 1, e.g. public const string Foo = "Foo";. If you change that to public const string Foo = "Bar", but don't recompile assemblies using the constant, those assemblies will still use a value of "Foo". (This goes for default values of optional parameters, too.)

这篇关于试图了解跨越程序集的方法签名更改的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆