考虑以下方法:
static void Invoke<TArg>(Action<TArg> action, TArg arg) => action(arg);
我知道;看起来没什么用,但它是实际代码的简化。
无论如何,我需要从具有按引用参数的方法调用
Invoke
,并为 action
传递 lambda。我需要某种方法从 lambda 内部返回按引用参数的值。最后,lambda 必须是 static
(非捕获)。
我想出了以下古怪的方案:
static unsafe void UpdateFooAndGetBar(ref object foo, out object bar) {
var args = (foo, bar: (object)null);
Invoke(
static pArgs => {
ref var args = ref Unsafe.AsRef<(object, object)>(pArgs.ToPointer());
args.Item1 = 123;
args.Item2 = "baz";
},
new IntPtr(Unsafe.AsPointer(ref args))
);
foo = args.foo;
bar = args.bar;
}
这似乎有用,但是
Unsafe
让我紧张。那么,我的代码合法吗?有更好的办法吗?
假设我们有一个自定义委托,允许按引用使用:
delegate void ActionByRef<T>(ref T value);
然后我们可以在我们的
Invoke
中使用它:
static void Invoke<T>(ActionByRef<T> callback, ref T args)
=> callback(ref args); // TODO any other logic
并使用它没有任何非托管指针:
public static void UpdateFooAndGetBar(ref object foo, out object bar)
{
var args = (foo, bar: (object)null);
Invoke(
static (ref (object foo, object bar) args) => {
args.Item1 = 123;
args.Item2 = "baz";
},
ref args
);
foo = args.foo;
bar = args.bar;
}
您还可以更进一步,拥有一个符合您确切需求的自定义委托,但这可重用性较差。