ChatGPT解决这个技术问题 Extra ChatGPT

Why doesn't C# support the return of references?

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:

static ref int Max(ref int x, ref int y) 
{ 
  if (x > y) 
    return ref x; 
  else 
    return ref y; 
} 
um...citation please?
C# has value and reference types and both can be returned what do you mean.
I'm talking about something like return ref x
After 4 years, you can do exactly this with C# 7 :)

C
Community

This question was the subject of my blog on June 23rd 2011. Thanks for the great question!

The C# team is considering this for C# 7. See https://github.com/dotnet/roslyn/issues/5233 for details.

UPDATE: The feature made it in to 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.)

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.

It is entirely possible to create a version of C# which supports both these features. You could then do things like

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.

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:

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.

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++?)


@EricLippert: I have no convincing example is just something I was wondering. Excellent and compelling response
@Eric: In your excample, wouldn't be more suitable to keep y alive after returning from M2? I would expect this feature to work like lambdas capturing locals. Or is the behavior you proposed because it is how CLR handles that scenario?
@Eric: IMHO the ability to have properties return references to value types is a major omission in the .net languages. If Arr is an Array of a value type (e.g. Point), one can say e.g. Arr(3).X=9 and know that one hasn't changed the value of Arr(9).X or even SomeOtherArray(2).X; if Arr were instead an array of some reference type, no such guarantees would exist. The fact that an array's indexing operator returns a reference is extremely useful; I consider it highly unfortunate that no other type of collection can provide such functionality.
Eric, what is the best way to provide the feedback regarding scenarios (as you suggest in the last paragraph) to maximize the chances that it's seen? MS Connect? UserVoice (with its arbitrary 10 post/vote limit)? Something else?
@ThunderGr: That is the C# philosophy for "unsafe" -- if you write code that is possibly memory-unsafe then C# insists that you mark it as "unsafe", so that you are taking responsibility for memory safety. C# already has the unsafe version of the feature, provided that the variable in question is of unmanaged type. The question is whether the C# team should make a unsafe version that handles managed types. If doing so makes it easy for the developer to write terrible bugs, it's not going to happen. C# is not C++, a language which makes it easy to write terrible bugs. C# is safe by design.
R
Rick Sladkey

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:

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.

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.


Tom is asking about methods that return a reference to a variable. The variable need not be of value type, though of course that is usually what people want when they want ref-returning methods. Otherwise, great analysis; you are correct that the only place in the C# language where a complex expression produces a ref to a variable that the user can then manipulate is the array indexer. (And of course the member access operator "." between a receiver and a field, but that's pretty obviously an access to a variable.)
E
Eladian

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...
}

C
Community

C# 7.0 has support for returning references. See my answer here.