Ran*_*dom 6 c# syntax task task-parallel-library
我代表一个"小"的语法问题,无法弄清楚如何正确地写出我想要的东西.
我有以下方法:
public void DoSomeMagic(string foo, ref string bar)
{
//DoSomeMagic...
}
Run Code Online (Sandbox Code Playgroud)
现在我想在Task.Run中卸载这段代码我通常会编写以下代码:
public async void Button_Click(object sender, EventArgs args)
{
string foo = "Hello Foo";
string bar = "Hello Bar";
await Task.Run(() => DoSomeMagic(foo, ref bar));
}
Run Code Online (Sandbox Code Playgroud)
这不编译告诉我:"不能在匿名方法体内使用'ref'或'out'参数'bar'"
所以我想为什么甚至做()=>因为我只是调用方法,我可以将它减少到这个:
Task.Run(DoSomeMagic(foo, ref bar));
Run Code Online (Sandbox Code Playgroud)
这再次没有编译告诉我:无法解析方法'Run(void)',候选者是:Run(Action)和Run(Func)
所以再一次没有问题Visual Studio你的需求是我的命令.
并将代码更改为:
Task.Run((Action)DoSomeMagic(foo, ref bar));
Run Code Online (Sandbox Code Playgroud)
再次没有编译告诉我:不能将'void'类型的表达式转换为'Action'类型,
好的,这开始变得棘手......
我试图而不是返回void我将尝试int并转换为Func给我错误:无法将类型'int'的表达式转换为'Func'类型
看到那个人来了,但我想让我们试一试:
所以我尝试了以下方法:
public Action CallDoSomeMagic(string foo, ref string bar)
{
//DoSomeMagic...
return new Action(() => DoSomeMagic(foo, ref bar));
}
Task.Run(CallDoSomeMagic);
Run Code Online (Sandbox Code Playgroud)
但这又给了我一个消息"不能在匿名方法体内使用'ref'或'out'参数'bar'"
由于每次尝试我的头痛都在增加,我想你们可以帮助我.它甚至可能吗?
Mar*_*ell 10
正如消息所说:你不能这样做.
你可以采取一个副本的参数值,并捕获这,例如:
public Action CallDoSomeMagic(string foo, ref string bar)
{
var snapshot = bar;
return new Action(() => DoSomeMagic(foo, ref snapshot));
}
Run Code Online (Sandbox Code Playgroud)
但请注意,更新将snapshot在调用者外部不可见bar.
原因有两方面:
首先,在lambda上使用的捕获变量成为编译器生成的上下文类中的字段.这适用于非ref/out参数,因为它们已经具有复制语义.所以在我的snapshot例子中,这实际上是:
var ctx = new CompilerGeneratedContextClassWithHorribleName();
ctx.foo = foo;
ctx.snapshot = bar;
return new Action(ctx.CompilerGeneratedMethod);
Run Code Online (Sandbox Code Playgroud)
在哪里CompilerGeneratedMethod:
DoSomeMagic(foo, ref snapshot);
Run Code Online (Sandbox Code Playgroud)
这对于refs是不可能的,因为你基本上需要该字段作为对字符串引用的引用,这是......凌乱的.
但更重要的是:考虑来电者的生命周期.这可能是:
void SomeMethod() {
string s = "abc";
CallDoSomeMagic("def", ref s);
}
Run Code Online (Sandbox Code Playgroud)
特别要注意的是,即使稍后调用委托,代码也需要工作 - 事实上我们可能会在你的情况下期望它,因为它涉及Task和async.现在:如果SomeMethod已经退出:对字符串引用指向的引用在哪里?提示:它只是堆栈中的任意位置,现在超出范围.
只给一个简单的解决办法:不是传球ref string bar,考虑通过SomeType obj,在那里obj.Bar是string你想; 即
public Action CallDoSomeMagic(string foo, SomeType obj)
{
return new Action(() => DoSomeMagic(foo, obj));
}
public void DoSomeMagic(string foo, SomeType obj)
{
// read and write obj.Bar here
}
Run Code Online (Sandbox Code Playgroud)
请注意foo,obj.Foo如果您愿意,也可以转到.
| 归档时间: |
|
| 查看次数: |
2274 次 |
| 最近记录: |