在Common Lisp中你可以这样做:
(defun foo (bar &key baz quux)
(list bar baz quux))
(foo 1 :quux 3 :baz 2) ; => (1 2 3)
Run Code Online (Sandbox Code Playgroud)
Clojure没有关键字参数.一种选择是:
(defn foo [bar {:keys [baz quux]}]
(list bar baz quux))
(foo 1 {:quux 3 :baz 2}) ; => (1 2 3)
Run Code Online (Sandbox Code Playgroud)
这是太多的嵌套括号,必须一直打字和阅读.它还需要将显式散列映射作为参数而不是平面列表传递.
什么是最惯用的Clojure相当于关键字参数,看起来没有人引发标点炸弹?
当我试图在Action委托中使用params时......
private Action<string, params object[]> WriteToLogCallBack;
Run Code Online (Sandbox Code Playgroud)
我收到了这个设计时错误:
类,结构或接口成员声明中的标记'params'无效
任何帮助!
我知道params
修饰符(将数组类型的一个参数转换为所谓的"参数数组")特别不是方法签名的一部分.现在考虑这个例子:
class Giraffid
{
public virtual void Eat(int[] leaves)
{
Console.WriteLine("G");
}
}
class Okapi : Giraffid
{
public override void Eat(params int[] leaves)
{
Console.WriteLine("O");
}
}
Run Code Online (Sandbox Code Playgroud)
编译时没有任何警告.然后说:
var okapi = new Okapi();
okapi.Eat(2, 4, 6); // will not compile!
Run Code Online (Sandbox Code Playgroud)
给出一个错误(No overload for method 'Eat' takes 3 arguments
).
现在,我知道编译器会将params
修改器转换为System.ParamArrayAttribute
相关参数的应用程序.通常,将一个属性集合应用于虚方法的参数,然后在具有不同属性集的派生类中的重写方法中装饰"对应"参数是没有问题的.
然而,编译器选择params
静默忽略我的关键字.相反,如果一个使它反过来,并且应用于params
基类中的参数Giraffid
,然后省略覆盖中的关键字Okapi
,编译器选择用它来装饰两个方法System.ParamArrayAttribute
.当然,我用IL DASM验证了这些东西.
我的问题:
这是记录在案的行为?我已经彻底搜索了C#语言规范,但没有发现任何提及.
我可以说至少Visual Studio开发环境对此感到困惑.当键入2, 4, 6
在上述方法的调用,所述 …
在C#中,我试图使用<see cref ="blah"/>来引用包含params关键字的方法签名.我知道这会将参数列表转换为数组,但我甚至无法弄清楚如何在CREF属性中引用数组.我在搜索中找不到任何内容,也不知道我知道的任何人.编译器在方括号上窒息.我已经尝试了各种不同的组合,使用花括号,使用Array类,但没有任何工作.有谁知道这个?
我最近开始探索lambda表达式,我想到了一个问题.假设我有一个需要不确定数量参数的函数.我会使用params关键字来建模可变数量的参数.
我的问题:我可以用Lambda表达式做类似的事情吗?例如:
Func<int[], int> foo = (params numbers[]) =>
{
int result;
foreach(int number in numbers)
{
result += numbers;
}
return result;
}
Run Code Online (Sandbox Code Playgroud)
如果是这样,两个子问题就出现了 - 是否有一种'好'的方式来编写这样的表达式,我甚至想在某个时候写出这样的表达式?
我正在尝试将C#5.0来电者信息与C#params关键字结合起来.目的是为日志框架创建一个包装器,我们希望记录器像String.Format一样格式化文本.在以前的版本中,方法如下所示:
void Log(
string message,
params object[] messageArgs = null);
Run Code Online (Sandbox Code Playgroud)
我们称之为:
log.Log("{0}: I canna do it cap'n, the engines can't handle warp {1}!",
"Scotty", warpFactor);
Run Code Online (Sandbox Code Playgroud)
现在,我们想要捕获调用者信息并记录它们.签名变为:
void Log(
string message,
params object[] messageArgs,
[CallerMemberName] string sourceMemberName = null);
Run Code Online (Sandbox Code Playgroud)
这不会编译,因为参数必须是最后一个参数.所以我试试这个:
void Log(
string message,
[CallerMemberName] string sourceMemberName = null,
params object[] messageArgs);
Run Code Online (Sandbox Code Playgroud)
有没有办法在没有提供sourceMembername的情况下调用它,或者将messageArgs参数显式指定为命名参数?这样做会破坏params关键字的用途:
// params is defeated:
log.Log("message",
messageArgs: new object[] { "Scotty", warpFactor });
// CallerMemberName is defeated:
log.Log("message", null,
"Scotty", warpFactor);
Run Code Online (Sandbox Code Playgroud)
有没有办法做到这一点?似乎传递调用者信息的"hacky"方式排除了使用params关键字.如果C#编译器认识到调用者成员信息参数根本不是真正的参数,那将是很棒的.我认为没有必要明确地传递它们.
我的备份将跳过params关键字,并且调用者必须在最后一个示例中使用长签名.
我有这样的方法:
public void Foo(params string[] args) {
bar(args[0]);
bar(args[1]);
}
Run Code Online (Sandbox Code Playgroud)
新要求会导致这样的变化:
public void Foo(string baz, params string[] args) {
if("do bar".Equals(baz)) {
bar(args[0]);
bar(args[1]);
}
}
Run Code Online (Sandbox Code Playgroud)
问题是即使我已经更改了方法签名,也没有发生编译错误,当然这是正确的,但是我希望每次调用没有指定Foo
参数的方法时都会出现编译错误baz
.也就是说,如果Foo
在更改之前的呼叫是这样的:
Foo(p1,p2); //where p1 and p2 are strings
Run Code Online (Sandbox Code Playgroud)
它现在需要是这个:
Foo(baz,p1,p2);
Run Code Online (Sandbox Code Playgroud)
如果它不会以这种方式改变,p1
则将被赋值给baz
,并且params数组args
的长度为1,并且OutOfBounds
将抛出异常.
更改签名并确保所有调用代码都相应更新的最佳方法是什么?(真实场景是Foo
许多项目共享的程序集中的生命自动构建在构建服务器上.编译错误因此是检测需要触及的所有代码以容纳更改的简单方法.)
编辑: 正如Daniel Mann和其他人指出的那样,上面的例子表明我根本不应该使用params.所以我应该解释一下,在我的真实世界的例子中,并不总是args需要有两个元素的情况,就Foo中的逻辑而言,args可以包含任意数量的元素.所以我们说这是Foo:
public void Foo(string baz, params string[] args) {
if("do bar".Equals(baz)) {
int x = GetANumberDynamically();
for(int i = 0; i<x; i++)
bar(args[i]);
} …
Run Code Online (Sandbox Code Playgroud) 我想做那样的事情:
public string GetMessage(params object otherValues[]) {
return String.Format(this.Message, this.FirstValue, otherValues);
}
Run Code Online (Sandbox Code Playgroud)
所以,我想修复一系列参数,String.Format()
但添加一个新参数.
什么是最好的方法,知道我们可以"重建"一个新的对象数组,这似乎并不好.
我看了一下Path.Combine
,注意到它有四个重载:
string
, string
string
,string
,string
string
,string
,string
,string
params string[]
前三个重载如何有用?
我看到它的方式,第四次超载使其他人毫无意义.我查看了源代码,我确实看到第四个重载的实现有点不同,但即使在这种情况下,我也希望只有一个params
重载决定根据数组的长度使用哪个实现.
public class SomeClass
{
public SomeClass(SomeType[] elements)
{
}
public SomeClass(params SomeType[] elements)
{
}
}
Run Code Online (Sandbox Code Playgroud)
我打印了这段代码并得到了CS0111错误。我很奇怪,难道SomeType[] elements
和params SomeType[] elements
同样的说法?
params-keyword ×10
c# ×9
.net ×2
action ×1
binding ×1
clojure ×1
closures ×1
common-lisp ×1
delegates ×1
lambda ×1
lisp ×1
overloading ×1
overriding ×1
params ×1
xml-comments ×1