考虑这样的方法
public void updateDSField<T>(string fieldName, T newVal)
{
// updates field in dataset
var col = TheDataTable.Columns[fieldName];
foreach (DataRow row in TheDataTable.Rows) row[col] = newVal; // * this marks the rows to be update by the commandtext
// create adapter and update string
TheAdapter.UpdateCommand = TheConn.CreateCommand();
string newValString = newVal.ToString();
if (typeof(T) == typeof(string)) newValString = "'" + newValString + "'";
TheAdapter.UpdateCommand.CommandText = "UPDATE [" + TheTableName + "] SET [" + fieldName + "] =" + newValString;
TheAdapter.Update(TheDS); // this will only update those rows marked by step * above
}
我喜欢在调用它们时明确命名这样的方法的参数,因为人们很容易混淆void RegisterUser(string firstname, string lastname, int age);
和firstname
参数。但是,lastname
并不是必需的。例如,我认为从清晰的角度来看,这应该没问题。
age
但是会抛出以下错误:
在指定了所有固定参数后,必须出现命名参数规范
另一件有趣的事情是,如果签名是
RegisterUser(firstname: "John", lastname: "Smith", 25);
然后按如下方式调用它不会抛出错误
void RegisterUser(int age, string firstname, string lastname);
为什么C#设计得像这样?如果允许第一个场景,是否存在编译器的复杂性?
答案 0 :(得分:14)
编译器可能能够解决它,但对于我们仅仅是人类来说,几乎不可能知道25是指第一个参数还是第三个参数。特别是因为它打开了混合参数的可能性。为什么不
MyFunction(firstname: "josh", 25, "smith", someotherargument: 42)
你怎么解释这个,25岁的年龄和史密斯的名字?为它制定规则,编译器可以实现它。但对人类来说有什么意义呢。代码混淆不应该那么容易
语言应该很难犯错误,而不是更容易
注意:如果之前的参数稍后被命名,则排序会发生奇怪的事情。 (就像我的例子中的名字和史密斯一样),因为这会成为你未命名的参数映射到正确参数的难题。它可以完成,但代码不应该产生谜题
答案 1 :(得分:6)
这是因为当您命名参数时,编译器会根据名称对其进行映射,并且只要存在所有必需的参数,就会忽略函数定义。在你的情况下,它不知道25是什么。对我们而言,它必须是年龄似乎是合乎逻辑的,但是如果你将你的例子改为:
void RegisterUser(string firstname, string lastname, int age = 0, int weight = 0);
然后说:
RegisterUser(firstname: "John", lastname: "Smith", 25);
然后编译器不知道如何处理最后一个25.这种调用函数的方法主要用于具有很多默认值的函数,你只想设置一些。
如果没有命名你的论据,你基本上就是说你严格遵循函数定义所设置的结构。
答案 2 :(得分:2)
预期用途,包括:
void M(int a = -1, int b = -1, int c = -1, int d = -1, int e = -1);
作为示例,您可以通过位置表示法指定这些可选参数的子集:
M(42, 28, 101); // gives a, b, and c in order; omits d and e
或者您可以使用命名参数:
M(d: 50, a: 42, c: 101); // gives three arguments in arbitrary order
或者您可以将它们组合在一起,从位置参数开始,然后切换到命名参数:
M(42, 28, e: 65537, d: 50); // mixed notation OK
您遇到限制的原因是:
M(c: 101, 7, 9, b: 28, 666); // ILLEGAL!
会让人感到困惑。
我可以看到你建议在特定的调用中保持位置排序,然后为了清楚起见,仅包括一些参数的名称。但是,似乎这种用法不是语言设计者的优先考虑。
我建议你在使用命名样式的原因是清晰的时候命名所有参数(而不是只需要指定适当的参数子集)。
答案 3 :(得分:1)
所有命名参数必须在位置参数之后;你不能在样式之间切换。位置参数始终引用方法声明中的相应参数。您不能通过稍后使用命名参数指定位置参数来跳过参数。编译器使用临时局部变量。然后它在参数槽中重新排序那些本地,我的猜测是编译器按顺序通过参数绑定,直到它找到一个命名参数,然后它丢弃它已经绑定而没有名称的参数,并在编译器使用临时局部变量时重新排序。通过名称绑定其余部分,例如它与年龄绑定25然后重新排序名字:“John”,姓氏:“Smith”
答案 4 :(得分:1)
位置参数放在命名参数之前。 位置参数始终引用方法声明中的相应参数。
假设我的方法是:
void Dimensions(int height, int breadth , int length);
我称之为
Dimensions(3, length: 12, 24);
在这种情况下:
&#39; 3&#39;是第一个参数,指的是身高,但是&#39; 24&#39;是第三个参数,指的是长度,但我们已经指定了长度值。
所以也许要克服这个障碍,默认情况下,c#style是在开始时定位位置参数以提供正确的引用。
另外,如果我们定义可选参数,最后提供位置参数可能会导致错误的结果。
答案 5 :(得分:0)
我认为这种情况下的语言设计驱动任何函数的第一个命名参数。
使用您的示例
void RegisterUser(int age, string firstname, string lastname);
并将其称为
RegisterUser(25, firstname: "John", lastname: "Smith");
在遇到第一个参数之前,编译器根本不知道该函数是否会使用任何命名参数。因此,编译器进行顺序映射是一个安全的假设。
<强> 25 强>
编译器获取第一个参数,如果它是非命名的,那么它将立即与函数定义中的第一个参数进行映射。
<强>姓名:强>
一旦遇到它的第一个命名参数,事情就会发生变化,因为编译器现在必须检查函数定义中提到的所有剩余参数,以映射当前的命名参数。
在成功映射它的第一个命名参数后,顺序映射的跟踪已被破坏。因此,现在为编译器提供非命名参数是不可行的,因为它现在无法确定映射它的位置。
如果您认为它应该记住最后一个非命名参数并从那里开始顺序映射,那么该错误也会发生错误,因为刚定义的命名参数也可能顺序正确。
<强>名字:强>
对于命名的论据来说,这是一件轻而易举的事。
希望这会有所帮助:)