.net 下层调用方是否能够从用C# 4.0生成的程序集中的可选参数中获益?

flseospp  于 2022-11-19  发布在  .NET
关注(0)|答案(3)|浏览(99)

假设我有一个现有的程序集,其中一些类有重载的方法,并为其中一些重载假定了默认的行为或值。

Type2 _defaultValueForParam2 = foo;
Type3 _defaultValueForParam3 = bar;

public ReturnType TheMethod(Type1 param1)
{
   return TheMethod(param1, _defaultValueForParam2);
}
public ReturnType TheMethod(Type1 param1, Type2 param2)
{
   return TheMethod(param1, param2, _defaultValueForParam3);
}
public ReturnType TheMethod(Type1 param1, Type2 param2, Type3 param3)
{
   // actually implement the method here. 
}

我知道C#中的可选参数应该让我将其合并到一个方法中。如果我生成一个方法,其中一些参数标记为可选,它是否可以与程序集的下层调用方一起工作?

EDIT:我所说的“工作”是指,一个 * 下层调用者 *,一个用C# 2.0或3.5编译器编译的应用程序,将能够用一个、两个或三个参数调用该方法,就像我使用了重载一样,下层编译器不会抱怨。

我确实想重构并消除库中的所有重载,但我不想强制使用重构库的下层调用方提供每个参数。

gkl3eglg

gkl3eglg1#

我没有读过关于新语言标准的文档,但是我假设4.0之前的调用程序必须传递所有声明的参数,就像现在一样。这是因为参数传递的工作方式。
当你调用一个方法时,参数被压入堆栈。如果传递了三个32位参数,那么12个字节将被压入堆栈;如果传递了四个32位参数,则会将16个字节压入堆栈。2压入堆栈的字节数在调用中是隐式的:被调用方假定传递了正确数量的参数。
因此,如果一个函数有4个32位参数,它会在调用者返回地址之前的16个字节处查看堆栈。如果调用者只传递了12个字节,那么被调用者将读取调用之前堆栈上的4个字节。它无法知道所有预期的16个字节都没有传递。
这就是它现在的工作方式,对于现有的编译器来说是没有改变的。
要支持可选参数,必须执行以下两项操作之一:
1.调用方可以传递一个附加值,该值显式地告诉被调用方有多少参数(或字节)被推送到堆栈上。然后,被调用方可以为任何省略的参数填充默认值。
1.调用方可以继续传递所有声明的参数,用默认值(从被调用方的元数据中读取)替换代码中省略的任何可选参数。然后,被调用方从堆栈中读取所有参数值,就像现在一样。
我怀疑它将被实现为(2).这与C中的做法类似(尽管缺少元数据的C要求在头文件中指定默认参数),该选项更有效(1),因为这都是在编译时完成的,并且不需要将额外的值压入堆栈,并且是最直接的实现。(2)如果默认值改变,所有调用程序都必须重新编译,否则它们将继续传递旧的默认值,因为它们已经被编译成常量了。这和现在公共常量的工作方式很相似。注意选项(1)没有这个缺点。
选项(1)也不支持命名参数传递,因此给定如下声明的函数:

static void Foo(int a, int b = 0, int c = 0){}

可以这样称呼它:

Foo(1, c: 2);

可以修改选项(1),使额外的隐藏值成为省略参数的位图,其中每一位代表一个可选参数。这任意地限制了一个函数可以接受的可选参数的数量,尽管这个限制至少是32个,这可能不是一件坏事。但是,它确实使这不太可能是实际的实现。
给定任一实现,调用代码必须理解可选参数的机制,以便在调用中省略任何参数。另外,对于选项(1),必须传递一个额外的隐藏参数,旧的编译器甚至不知道这个参数,除非它作为形式参数添加到元数据中。

axr492tv

axr492tv2#

在C# 4.0中,当省略可选参数时,将替换该参数的默认值,即:

public void SendMail(string toAddress, string bodyText, bool ccAdministrator = true, bool isBodyHtml = false)
{ 
    // Full implementation here   
}

对于您的下层呼叫端,这表示如果他们使用其中一个遗漏参数的变数,c#会 * 取代您为遗漏参数 *. This article explains the process in greater detail提供的预设值。
您现有的下层调用应该仍然有效,但you will have to recompile your clients in c# 4.0除外。

ttp71kqs

ttp71kqs3#

我认为,如果用一个带可选参数的方法替换所有3个方法,那么使用库的代码仍然可以工作,但是需要重新编译。

相关问题