I have read that .NET supports return of references, but C# doesn't. Is there a special reason? Why I can't do something like:
我读过。net支持引用的返回,但是c#不支持。有什么特别的原因吗?为什么我做不到:
static ref int Max(ref int x, ref int y) { if (x > y) return ref x; else return ref y; }
4 个解决方案
#1
186
This question was the subject of my blog on June 23rd 2011. Thanks for the great question!
这个问题是我2011年6月23日博客的主题。谢谢你的问题!
The C# team is considering this for C# 7. See https://github.com/dotnet/roslyn/issues/5233 for details.
c#团队正在为c# 7考虑这个问题。有关详细信息,请参阅https://github.com/dotnet/roslyn/issues/5233。
UPDATE: The feature made it in to C# 7!
更新:这个特性使它变成c# 7!
You are correct; .NET does support methods that return managed references to variables. .NET also supports local variables that contain managed references to other variables. (Note however that .NET does not support fields or arrays that contain managed references to other variables because that overly complicates the garbage collection story. Also the "managed reference to variable" types are not convertible to object, and therefore may not be used as type arguments to generic types or methods.)
你是正确的;. net支持返回对变量的托管引用的方法,. net也支持包含对其他变量的托管引用的本地变量。(请注意,. net不支持包含对其他变量的托管引用的字段或数组,因为这使垃圾收集的故事变得过于复杂。此外,“对变量的托管引用”类型不能转换为对象,因此不能用作泛型类型或方法的类型参数。
Commenter "RPM1984" for some reason asked for a citation for this fact. RPM1984 I encourage you to read the CLI specification Partition I Section 8.2.1.1, "Managed pointers and related types" for information about this feature of .NET.
评论人“RPM1984”出于某种原因要求引用这一事实。RPM1984我鼓励您阅读CLI规范分区I节8.2.1.1,“托管指针和相关类型”,以了解关于. net的这个特性的信息。
It is entirely possible to create a version of C# which supports both these features. You could then do things like
创建一个支持这两个特性的c#版本是完全可能的。你可以这样做
static ref int Max(ref int x, ref int y) { if (x > y) return ref x; else return ref y; }
and then call it with
然后调用它
int a = 123;int b = 456; ref int c = ref Max(ref a, ref b); c += 100;Console.WriteLine(b); // 556!
I know empirically that it is possible to build a version of C# that supports these features because I have done so. Advanced programmers, particularly people porting unmanaged C++ code, often ask us for more C++-like ability to do things with references without having to get out the big hammer of actually using pointers and pinning memory all over the place. By using managed references you get these benefits without paying the cost of screwing up your garbage collection performance.
我从经验上知道,构建一个支持这些特性的c#版本是可能的,因为我已经这么做了。高级程序员,特别是移植非托管c++代码的人,常常要求我们提供更多类似c++的能力,以便在不需要真正使用指针和到处固定内存的情况下处理引用。通过使用托管引用,您可以获得这些好处,而无需为提高垃圾收集性能付出代价。
We have considered this feature, and actually implemented enough of it to show to other internal teams to get their feedback. However at this time based on our research we believe that the feature does not have broad enough appeal or compelling usage cases to make it into a real supported language feature. We have other higher priorities and a limited amount of time and effort available, so we're not going to do this feature any time soon.
我们已经考虑了这个特性,并实际实现了足够的特性,以便向其他内部团队展示以获得他们的反馈。然而,基于我们的研究,我们认为该特性并没有足够的吸引力或引人注目的使用案例使其成为真正受支持的语言特性。我们有其他更高的优先级和有限的时间和精力,所以我们不会很快做这个功能。
Also, doing it properly would require some changes to the CLR. Right now the CLR treats ref-returning methods as legal but unverifiable because we do not have a detector that detects this situation:
此外,正确地执行它将需要对CLR进行一些更改。目前CLR认为返返返弹方法是合法的,但无法证实,因为我们没有检测这种情况的探测器:
ref int M1(ref int x){ return ref x;}ref int M2(){ int y = 123; return ref M1(ref y); // Trouble!}int M3(){ ref int z = ref M2(); return z;}
M3 returns the contents of M2's local variable, but the lifetime of that variable has ended! It is possible to write a detector that determines uses of ref-returns that clearly do not violate stack safety. What we would do is write such a detector, and if the detector could not prove stack safety, then we would not allow the usage of ref returns in that part of the program. It is not a huge amount of dev work to do so, but it is a lot of burden on the testing teams to make sure that we've really got all the cases. It's just another thing that increases the cost of the feature to the point where right now the benefits do not outweigh the costs.
M3返回M2的局部变量的内容,但是该变量的生命周期已经结束!可以编写一个检测器来确定ref-return的使用,它显然不会违反堆栈安全。我们要做的是编写这样一个检测器,如果检测器不能证明堆栈安全,那么我们就不允许在程序的那个部分使用ref返回。这样做并不需要花费大量的开发工作,但是要确保我们确实拥有了所有的案例,对测试团队来说是很大的负担。这只是增加特性的成本的另一件事,现在的好处并没有超过成本。
If you can describe for me why it is you want this feature, I would really appreciate that. The more information we have from real customers about why they want it, the more likely it will make it into the product someday. It's a cute little feature and I'd like to be able to get it to customers somehow if there is sufficient interest.
如果你能告诉我为什么你想要这个功能,我会很感激的。我们从真正的客户那里得到的关于他们为什么想要它的信息越多,它就越有可能在某一天成为产品。这是一个可爱的小功能,如果有足够的兴趣,我希望能以某种方式把它带给客户。
(See also related questions Is it Possible to Return a Reference to a Variable in C#? and Can I use a reference inside a C# function like C++?)
(请参见相关问题,是否可能在c#中返回对变量的引用?我可以在c#函数中使用一个引用,比如c++吗?
#2
22
You are talking about methods that return a reference to a value type. The only built-in example in C# that I know of is the array-accessor of a value type:
您正在讨论返回值类型引用的方法。我所知道的c#中唯一的内置示例是值类型的array-accessor:
public struct Point{ public int X { get; set; } public int Y { get; set; }}
and now create an array of that struct:
现在创建这个结构的数组:
var points = new Point[10];points[0].X = 1;points[0].Y = 2;
In this case points[0]
, the array indexer, is returning a reference to struct. It is impossible to write your own indexer (for example for a custom collection), that has this same "return a reference" behavior.
在这个例子中,点[0],数组索引器,返回一个对struct的引用。不可能编写自己的索引器(例如自定义集合),它具有相同的“返回引用”行为。
I didn't design the C# language so I don't know all the reasoning behind not supporting it, but I think that the short answer might be: we can get along just fine without it.
我没有设计c#语言,所以我不知道为什么不支持它,但我认为简短的回答可能是:没有它我们可以过得很好。
#3
1
You could always do something like:
你可以这样做:
public delegate void MyByRefConsumer<T>(ref T val);public void DoSomethingWithValueType(MyByRefConsumer<int> c){ int x = 2; c(ref x); //Handle potentially changed x...}
#1
186
This question was the subject of my blog on June 23rd 2011. Thanks for the great question!
这个问题是我2011年6月23日博客的主题。谢谢你的问题!
The C# team is considering this for C# 7. See https://github.com/dotnet/roslyn/issues/5233 for details.
c#团队正在为c# 7考虑这个问题。有关详细信息,请参阅https://github.com/dotnet/roslyn/issues/5233。
UPDATE: The feature made it in to C# 7!
更新:这个特性使它变成c# 7!
You are correct; .NET does support methods that return managed references to variables. .NET also supports local variables that contain managed references to other variables. (Note however that .NET does not support fields or arrays that contain managed references to other variables because that overly complicates the garbage collection story. Also the "managed reference to variable" types are not convertible to object, and therefore may not be used as type arguments to generic types or methods.)
你是正确的;. net支持返回对变量的托管引用的方法,. net也支持包含对其他变量的托管引用的本地变量。(请注意,. net不支持包含对其他变量的托管引用的字段或数组,因为这使垃圾收集的故事变得过于复杂。此外,“对变量的托管引用”类型不能转换为对象,因此不能用作泛型类型或方法的类型参数。
Commenter "RPM1984" for some reason asked for a citation for this fact. RPM1984 I encourage you to read the CLI specification Partition I Section 8.2.1.1, "Managed pointers and related types" for information about this feature of .NET.
评论人“RPM1984”出于某种原因要求引用这一事实。RPM1984我鼓励您阅读CLI规范分区I节8.2.1.1,“托管指针和相关类型”,以了解关于. net的这个特性的信息。
It is entirely possible to create a version of C# which supports both these features. You could then do things like
创建一个支持这两个特性的c#版本是完全可能的。你可以这样做
static ref int Max(ref int x, ref int y) { if (x > y) return ref x; else return ref y; }
and then call it with
然后调用它
int a = 123;int b = 456; ref int c = ref Max(ref a, ref b); c += 100;Console.WriteLine(b); // 556!
I know empirically that it is possible to build a version of C# that supports these features because I have done so. Advanced programmers, particularly people porting unmanaged C++ code, often ask us for more C++-like ability to do things with references without having to get out the big hammer of actually using pointers and pinning memory all over the place. By using managed references you get these benefits without paying the cost of screwing up your garbage collection performance.
我从经验上知道,构建一个支持这些特性的c#版本是可能的,因为我已经这么做了。高级程序员,特别是移植非托管c++代码的人,常常要求我们提供更多类似c++的能力,以便在不需要真正使用指针和到处固定内存的情况下处理引用。通过使用托管引用,您可以获得这些好处,而无需为提高垃圾收集性能付出代价。
We have considered this feature, and actually implemented enough of it to show to other internal teams to get their feedback. However at this time based on our research we believe that the feature does not have broad enough appeal or compelling usage cases to make it into a real supported language feature. We have other higher priorities and a limited amount of time and effort available, so we're not going to do this feature any time soon.
我们已经考虑了这个特性,并实际实现了足够的特性,以便向其他内部团队展示以获得他们的反馈。然而,基于我们的研究,我们认为该特性并没有足够的吸引力或引人注目的使用案例使其成为真正受支持的语言特性。我们有其他更高的优先级和有限的时间和精力,所以我们不会很快做这个功能。
Also, doing it properly would require some changes to the CLR. Right now the CLR treats ref-returning methods as legal but unverifiable because we do not have a detector that detects this situation:
此外,正确地执行它将需要对CLR进行一些更改。目前CLR认为返返返弹方法是合法的,但无法证实,因为我们没有检测这种情况的探测器:
ref int M1(ref int x){ return ref x;}ref int M2(){ int y = 123; return ref M1(ref y); // Trouble!}int M3(){ ref int z = ref M2(); return z;}
M3 returns the contents of M2's local variable, but the lifetime of that variable has ended! It is possible to write a detector that determines uses of ref-returns that clearly do not violate stack safety. What we would do is write such a detector, and if the detector could not prove stack safety, then we would not allow the usage of ref returns in that part of the program. It is not a huge amount of dev work to do so, but it is a lot of burden on the testing teams to make sure that we've really got all the cases. It's just another thing that increases the cost of the feature to the point where right now the benefits do not outweigh the costs.
M3返回M2的局部变量的内容,但是该变量的生命周期已经结束!可以编写一个检测器来确定ref-return的使用,它显然不会违反堆栈安全。我们要做的是编写这样一个检测器,如果检测器不能证明堆栈安全,那么我们就不允许在程序的那个部分使用ref返回。这样做并不需要花费大量的开发工作,但是要确保我们确实拥有了所有的案例,对测试团队来说是很大的负担。这只是增加特性的成本的另一件事,现在的好处并没有超过成本。
If you can describe for me why it is you want this feature, I would really appreciate that. The more information we have from real customers about why they want it, the more likely it will make it into the product someday. It's a cute little feature and I'd like to be able to get it to customers somehow if there is sufficient interest.
如果你能告诉我为什么你想要这个功能,我会很感激的。我们从真正的客户那里得到的关于他们为什么想要它的信息越多,它就越有可能在某一天成为产品。这是一个可爱的小功能,如果有足够的兴趣,我希望能以某种方式把它带给客户。
(See also related questions Is it Possible to Return a Reference to a Variable in C#? and Can I use a reference inside a C# function like C++?)
(请参见相关问题,是否可能在c#中返回对变量的引用?我可以在c#函数中使用一个引用,比如c++吗?
#2
22
You are talking about methods that return a reference to a value type. The only built-in example in C# that I know of is the array-accessor of a value type:
您正在讨论返回值类型引用的方法。我所知道的c#中唯一的内置示例是值类型的array-accessor:
public struct Point{ public int X { get; set; } public int Y { get; set; }}
and now create an array of that struct:
现在创建这个结构的数组:
var points = new Point[10];points[0].X = 1;points[0].Y = 2;
In this case points[0]
, the array indexer, is returning a reference to struct. It is impossible to write your own indexer (for example for a custom collection), that has this same "return a reference" behavior.
在这个例子中,点[0],数组索引器,返回一个对struct的引用。不可能编写自己的索引器(例如自定义集合),它具有相同的“返回引用”行为。
I didn't design the C# language so I don't know all the reasoning behind not supporting it, but I think that the short answer might be: we can get along just fine without it.
我没有设计c#语言,所以我不知道为什么不支持它,但我认为简短的回答可能是:没有它我们可以过得很好。
#3
1
You could always do something like:
你可以这样做:
public delegate void MyByRefConsumer<T>(ref T val);public void DoSomethingWithValueType(MyByRefConsumer<int> c){ int x = 2; c(ref x); //Handle potentially changed x...}