【发布时间】:2010-07-19 20:26:01
【问题描述】:
在 C++ 中我可以这样做:
int flag=0,int1=0,int2=1;
int &iRef = (flag==0?int1:int2);
iRef +=1;
具有 int1 递增的效果。
我必须修改一些较旧的 c# 代码,如果我能做类似的事情会非常有帮助,但我在想......也许不会。有人吗?
【问题讨论】:
在 C++ 中我可以这样做:
int flag=0,int1=0,int2=1;
int &iRef = (flag==0?int1:int2);
iRef +=1;
具有 int1 递增的效果。
我必须修改一些较旧的 c# 代码,如果我能做类似的事情会非常有帮助,但我在想......也许不会。有人吗?
【问题讨论】:
更新:下面讨论的功能终于在 C# 7 中添加了。
C# 不支持您想要的功能 - 制作托管局部变量别名。您可以使用 formal parameters 来实现 - 您可以创建作为任何变量别名的形式参数 - 但您不能创建作为任何变量别名的 local。
但是,没有技术上的困难阻止我们这样做; CLR 类型系统支持“引用局部变量”。 (它也支持 ref 返回类型,但不支持 ref 字段。)
几年前,我实际上写了一个 C# 的原型版本,它支持 ref locals 和 ref return 类型,它工作得非常好,所以我们有经验证据表明我们可以成功地做到这一点。但是,如果有的话,这个特性不太可能很快被添加到 C# 中。详情请见http://ericlippert.com/2011/06/23/ref-returns-and-ref-locals/。
我注意到,如果我是你,我会在任何语言中避免这种情况。编写两个变量共享相同存储空间的程序会导致代码难以阅读、难以理解、难以修改和难以维护。
【讨论】:
std::istream& is = blah() ? ifs : std::cin。我会用ifs 或std::cin 调用一个函数,但其他人似乎反对额外的函数调用。
您可以做到这一点-或者至少与您想要的非常相似-但最好找到另一种方法。例如,您可以将整数包装在一个简单的引用类型中。
如果您仍然想这样做,请参阅 Eric Lippert here 发布的 Ref<T> 课程:
sealed class 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); } }
}
public class Program
{
public static void Main()
{
int flag=0,int1=0,int2=1;
Ref<int> iRef = (flag == 0 ?
new Ref<int>(() => int1, z => { int1 = z; }) :
new Ref<int>(() => int2, z => { int2 = z; }));
iRef.Value += 1;
Console.WriteLine(int1);
}
}
输出:
1
【讨论】:
如果您只需要修改函数中的值类型,则使用 ref 关键字传递参数。
int i = 0;
void increment(ref int integer)
{
integer++;
}
increment(ref i);
【讨论】:
Ref<T> 类型(聪明的想法,+1 来自我)和一个接受 ref 参数的函数之间进行选择,我当然更喜欢一个函数。
是的,您可以使用 C# 7.0 做到这一点。它支持返回引用和存储引用。看我的回答here。
【讨论】:
不怕。您可以使用unsafe 代码和指针来做到这一点,如下所示:
int flag=0,int1=0,int2=1;
unsafe
{
int *iRef = (flag==0? &int1:&int2);
*iRef +=1;
}
(不是说这是个好主意或任何东西:))
【讨论】:
在 C# 中没有直接等效项。有几个选项 -
您可以使用unsafe code and pointers as suggested by dkackman。
另一种选择是使用保存值的引用类型(类)。例如:
// Using something like
public class Wrapped<T> {
public Wrapped(T initial) {
this.Value = initial;
}
public T Value { get; set; }
}
// You can do:
bool flag=false;
var int1 = new Wrapped<int>(0);
var int2 = new Wrapped<int>(1);
Wrapped<int> iRef = flag ? int2 : int1;
iRef.Value = iRef.Value + 1;
由于您正在使用对类的引用,因此对 iRef 的分配复制了引用,并且上述工作...
【讨论】:
您可以像这样使用Action delegate:
int flag = 0, int1 = 0, int2 = 0;
Action increment = flag == 0 ? (Action) (() => ++int1) : () => ++int2;
increment();
【讨论】: