C#内置的Action<>委托可以使用ref类型吗?

52

C# 中有内置委托 Action<>Func<>。是否可以在这些委托中使用 'ref' 类型的参数?例如,这段代码:

public delegate void DTest( ref Guid a );
public event DTest ETest;

代码能够编译通过。但如果我使用 Action<>,它将无法编译通过:

public event Action< ref Guid > ETest;

有什么提示吗?

2个回答

71
不,你不能在Action委托中使用传递引用的方式。虽然框架中有一个“按引用传递的类型”概念作为Type,但就C#而言,它并不是一个正常意义上的类型。如果你明白我的意思,ref是参数的修饰符,而不是类型名称的一部分。
不过,你可以构建自己的等效类型集合,例如:
delegate void ActionRef<T>(ref T item);

当然,如果你想在同一委托中混合使用引用参数和非引用参数,你会遇到一系列棘手的组合:
delegate void ActionRef1<T1, T2>(ref T1 arg1, T2 arg2);
delegate void ActionRef2<T1, T2>(T1 arg1, ref T2 arg2);
delegate void ActionRef3<T1, T2>(ref T1 arg1, ref T2 arg2);

这是使用lambda语法定义的唯一方式吗? ActionRef<int, int> Setter2 = (ref int x, int y) =>x = y; 它没问题,但比正常写法稍微长了一点。 - sgtz
1
@sgtz:我也这么怀疑——这是一个相当不寻常的要求,所以如果没有太多精简的工作,我也不会感到惊讶。 - Jon Skeet
“ref R[i]” 这种写法在 R 是 List<T> 的情况下可行吗?您希望我将其作为一个新问题提出来吗? - sgtz
嗨Jon,C# 7在这方面有什么变化吗?因为我在一个C# 6项目中使用了Action<ref Foo>,并从R#得到了一个错误,说它是C# 7的功能。这是他们的错误吗? - gdoron
@gdoron:我不知道有没有。在C# 7中,关于ref的新内容还是很多的,但是似乎没有那个... - Jon Skeet

8
只要您的引用是一个复杂对象(具有属性),就可以这样做。
示例对象:
public class MyComplexObject
{
    /// <summary>
    /// Name provided for the result.
    /// </summary>
    public string Name { get; set; }

    /// <summary>
    /// Value of the result.
    /// </summary>
    public object Value { get; set; }
}

应用于 Action 中:

Action<MyComplexObject> myAction = (MyComplexObject result) =>
{
    result.Value = MyMethodThatReturnsSomething();                                              
};

由于MyComplexObject引用未更改,数据得以保留。

同时也可以在我的博客上查看。


1
这并不是问题的真正答案,因为它会分配一个对象。如果有人使用 ref,他们必须有通过引用传递的原因... - Dvir
无论类是否具有属性,它们都是引用。问题是关于具有引用参数的操作(这些可能不是对象),这并不能解决问题——将类包装在属性周围根本不是一回事。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接