C#引用赋值运算符是什么?

4
例如:
        int x = 1;
        int y = x;
        y = 3;
        Debug.WriteLine(x.ToString());

第三行是否有任何参考运算符可以使得 x 赋值为 3,即使我已经将 y 赋值为 3。


没有。这个问题以前出现过,我记得Eric Lippert给出了一个很好的回答。 - user166390
3
你能解释一下为什么你需要这样的东西吗?值类型无法实现这个功能。 - Bala R
https://dev59.com/ZHM_5IYBdhLWcg3wWRkF - user166390
1
https://dev59.com/_0_Sa4cB1Zd3GeqP-C1F - user166390
1
@Bala R 这与值类型与引用类型无关。问题是关于创建一个变量的引用(正如在C++中可能),而不是关于对象的可变性...尽管通常有“更好的方法”来解决这个问题。 - user166390
谢谢PST,你上面提供的链接很好。 - Cheung
6个回答

10

我曾经写过一个 C# 的原型版本,其中包含该特性;你可以这样说:

int x = 123;
ref int y = ref x;

现在,x和y将成为同一变量的别名。

我们决定不将这个功能添加到语言中;如果您有一个非常棒的使用案例,我很乐意听取。

你不是第一个询问这个特性的人;有关更多细节,请参见Can I use a reference inside a C# function like C++?

更新:该功能可能会出现在C# 7中。


这是一个例子,如果能在循环外将x变为ij,那就更好了。http://i.imgur.com/W12AMCN.png - shinzou
在寻找完全相同的功能后,我发现了这个问题(和许多其他类似的问题)。我有一个我认为非常普通的情况,我无法找到一个合适的解决方法来使用引用。我想要的不涉及指针、内存地址或其他“复杂”的C++特性。我需要一个简单的(“盲目”的)引用(别名),更接近于C++中的#define。我也不对传递/返回函数引用感兴趣,因此也不会涉及堆栈相关的问题。看看我的情况: - mireazma
@mireazma:那么为什么不创建一个委托来写入变量呢?这样,您就可以表示对变量的访问,并且变量的生命周期将延长到委托实例的生命周期。 - Eric Lippert
请参阅提案:Ref Returns and Locals。请注意,该提案已于9月19日实现,并显示在https://learn.microsoft.com/en-us/dotnet/articles/csharp/csharp-7上。因此,这个功能可能在C# 7中可用。 - Brian
@mireazma:基本上它的工作原理是这样的:int x = 123; Action<int> set_x = new_x => { x = new_x; }; 现在当你想要改变 x 的值时,只需说 set_x(4567);x 的值就会改变。但是 set_x 是一个值;你可以将它放在一个字段、一个数组中,返回它,无论什么情况下,它都会保持 x 存活,直到不再需要为止。你可以把它看作是一个带有 setter 的装箱整数。 - Eric Lippert
显示剩余4条评论

4

“int”是一种值类型,因此在赋值时复制该值,正如您所发现的那样。

您可以使用传统C/C++中的指针,通过使用“unsafe”块,但是这些指针仅可在该块内部使用,从而限制了其使用。如果您希望在“unsafe”块之外访问该值,则需要转换为使用引用。

类似于以下内容...

var x = new Tuple<int>(1);
var y = x;
y.Item1 = 3;

请注意,如果x最初是类中的一个字段,则此解决方案可能不实用。在这种情况下,您可以使用Eric Lippert在回答类似问题时提供的此代码 - Brian
жіЁж„Ҹпјҡxе’ҢyеҸҜд»ҘжҳҜеј•з”Ёзұ»еһӢзҡ„еұҖйғЁеҸҳйҮҸпјҢеҗҢж ·зҡ„规еҲҷйҖӮз”ЁгҖӮйҮҚж–°еҲҶй…ҚyдёҚдјҡеҪұе“ҚxгҖӮе…ідәҺеҖјзұ»еһӢзҡ„еҶ…е®№жҳҜж— е…ізҙ§иҰҒзҡ„гҖӮ - Anthony Pegram

3

这并不完全符合你的需求,但我认为这可能会有帮助。如果您想在函数内使用指针别名,可以使用ref关键字来实现:

public static void RefExample(ref int y)
{
    y = 3;
}

main()
{
    int x = 5;
    RefExample(ref x);
    Console.WriteLine(x); // prints 3
}

3

您可以像在 C 中一样使用指针。

    int x = 1;
    unsafe
    {
        int* y = &x;
        *y = 3;
    }

    Debug.WriteLine(x.ToString());

(请注意,您必须使用不安全标志进行编译)

0

唯一的方法是使用“不安全”的代码,并实际使用指针。在 C# 中,指针不能存在于不安全代码块之外。然后,您应该能够像在 C/C++ 中一样使用指针。

请查看this页面以了解如何使用“不安全”代码块。


0
我想评论Eric Lippert的回答,但新用户无法评论帖子。所以,我认为我有这样的用途。
看一下这段代码:
private void SetGridColumns(ref RegistryKey targetKey, List<ColInfo> cols)
    {
        string targetKeyName = Path.GetFileName(targetKey.Name);
        m_grids.DeleteSubKeyTree(targetKeyName, false);
        targetKey.Close();
        targetKey = m_grids.CreateSubKey(targetKeyName);

//... }

    public void SetColumns(List<ColInfo> cols, bool youth)
    {
        RegistryKey key = youth ? m_youthGrid : m_mainGrid;
        SetGridColumns(ref key, cols);
    }

它应该像这样工作: 在SetColumns中,我根据“youth”参数调用SetGridColumns。我希望我的键首先被删除,然后重新创建。m_mainGrid当然是类的成员。 在这种情况下,确实删除并重新创建了键。但是在SetGridColumns中,只有“targetKey”被重新创建,而不是我的m_mainGrid。

因此,在这里我唯一能做的就是使用指针,这不是C#中首选的方式。 如果我只能这样做:

ref RegistryKey key = youth ? m_youthGrid : m_mainGrid;

一切应该正常工作。


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