是否可以在C#中返回对变量的引用?

Bet*_*moo 29 c# reference return-value

我可以返回对double值的引用吗?

这就是我想要做的:

ref double GetElement()
{
   ......
   // Calculate x,y,z
   return ref doubleArray[x,y,z];
}
Run Code Online (Sandbox Code Playgroud)

要像这样使用它

void func()
{
   GetElement()=5.0;
}
Run Code Online (Sandbox Code Playgroud)

这就像在C++中返回一个双指针......我知道我写它的方式是错误的......但是有没有正确的方法呢?

Eri*_*ert 43

更新:C#7现在支持所需的功能.


CLR类型系统确实支持ref-returns方法,我编写了一个C#编译器的实验原型,它支持你想要的功能.(原型还实现了ref-typed局部变量,但ref-typed字段在CLR类型系统中是非法的.)

你已经完全按照我为原型选择的语法,这意味着无论是伟大的思想是否相同,或者傻瓜永远不会有所不同.

尽管原型工作得非常好,但这不太可能使条形成为下一版C#语言的特性.很少有客户想要这个功能,实现起来相当昂贵,只要您拥有更重要的功能,我们就有一个列表,并且还有其他方法可以使这种事情发挥作用而不会在类型系统中增加这种复杂性.这些都是执行该功能的巨大"点".

例如,您可以创建一对代理:

struct Ref<T>
{
    private readonly Func<T> getter;
    private readonly Action<T> setter;
    public Ref(Func<T> getter, Action<T> setter)
    {
        this.getter = getter;
        this.setter = setter;
    }
    public T Value { get { return getter(); } set { setter(value); } }
}

var arr = new int[10];
var myref = new Ref<int>(()=>arr[1], x=>arr[1]=x);
myref.Value = 10;
Console.WriteLine(myref.Value);
Run Code Online (Sandbox Code Playgroud)

这比使用ref返回实现的相同功能要慢得多,但好处是你可以Ref<T>在ref不合法的地方建立一个.例如,您可以存储Ref<T>在一个字段中,您无法使用ref-returns方法.

如果你有一个真正令人敬畏的场景,为什么你需要 ref-returns方法,我很乐意听到它.我们拥有的现实场景越多,这种功能就越有可能在假设的未来版本的语言中实现.

另见相关问题:

我可以在像C++这样的C#函数中使用引用吗?

为什么C#不支持引用的返回?

和我关于这个主题的博客文章:

http://ericlippert.com/2011/06/23/ref-returns-and-ref-locals/

  • 我在概念上同意,但看起来像参考类型的可变结构对于效率是必不可少的.如果分配/释放一百万个参考实例的速度和百万个结构一样快,那就不是问题! (6认同)
  • @EricLippert:假设有一个带有`Int32`字段的可变类`PointClass`或称为`X`和`Y`的属性,一个有一个`IList <PointClass> myList`.是否有任何中途方面允许`myList [2] .X = 5;`工作而不允许外部代码在不通过`myList`的情况下对`myList [2] .X`进行修改?给定一个`IList <Point> myList2`,代码如`{var tmp = myList2 [2]; tmp.X = 5; myList [2] = tmp;`}比我想象的类更清晰,更安全.由于`Point`在语义上是一对整数,为什么不使用行为类似的数据类型呢? (2认同)

Tho*_*que 8

不,这在C#中是不可能的.您只能通过引用传递参数.

但是,您可以使用属性获得相同的结果:

double Element
{
    get { return doubleArray[x,y,z]; }
    set { doubleArray[x,y,z] = value; }
}

void func()
{
   Element = 5.0;
}
Run Code Online (Sandbox Code Playgroud)


Axa*_*dax 6

可以不安全的代码中执行它,并有一个返回指向double的指针的方法:

unsafe double* GetElementP(){
...
}
Run Code Online (Sandbox Code Playgroud)


Str*_*ior 6

C#中的值类型始终按值传递.对象始终按值传递其引用.Axarydax指出,这会改变"不安全"的代码.

避免此约束的最简单,最安全的方法是确保您的double以某种方式附加到对象.

public class MyObjectWithADouble {
    public double Element {get; set;} // property is optional, but preferred.
}

...
var obj = new MyObjectWithADouble();
obj.Element = 5.0
Run Code Online (Sandbox Code Playgroud)

我还想说一下,我对你如何预期将双重赋值给三维数组感到困惑.您可能想澄清一下您的目标.

我想我现在更了解你的目标.您希望返回给定数组中值的位置,然后能够更改该位置中的值.这种模式打破了C#的一些预期范式,因此我建议考虑其他方法来实现您正在寻找的东西.但如果它真的有意义,我会做更像这样的事情:

public class 3dArrayLocation {public int X; public int Y; public int Z;}

...

public 3dArrayLocation GetElementLocation(...)
{
    // calculate x, y, and z
    return new 3dArrayLocation {X = x, Y = y, Z = z}
}

...

var location = GetElementLocation(...);
doubleArray[location.X, location.Y, location.Z] = 5.0;
Run Code Online (Sandbox Code Playgroud)