runtime: Existing reflection APIs should be able to invoke ref-returning methods and return a value

Related to: https://github.com/dotnet/roslyn/issues/8489

The scenario seems to be explicitly forbidden. Possibly due to ref returning methods not being common in the past.

Note that this issue does not ask for a new API that would allow returning a ref.

This is just about the existing APIs that returns the result as an object. It seems that they should work with ref returning methods by evaluating the target, reading the value indirectly and returning the value as object.


object result1 = inst.RefReturningMethod();

// should be the same as 
object result2 = inst.GetType().InvokeMember(inst, . . ., "RefReturningMethod",. . .);

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 2
  • Comments: 36 (25 by maintainers)

Commits related to this issue

Most upvoted comments

Thanks everyone for the spirited debate.

I’m going to have to side with team NullReferenceException on this.

This particular api feature is about convenience and intuition and while the NullReferenceException approach makes the ref case a bit more “special” (*), it mirrors exactly the way that refs make early bound calls special. I don’t think it would be confusing. It also has the advantage of not adding new surface area or punning existing ones.

The TypeReferenced-based api will be the one that’s functionally complete and has consistent behavior for all types.

(*) It’s already special by virtue of the fact that we’re bundling an indirection and providing no access to the ref itself.

Is System.Reflection.Missing.Value used as argument going to turn into a null ref?

I think we could swing that. Today, passing Missing.Value to a ref Object parameter throws ArgumentException: Missing parameter does not have a default value. And I can’t see how we would support default values for ref parameters so there isn’t a chance for a conflict. Or we could invent a new sentinal value if necessary.

Getting Pointer back is still an unambiguous result given the signature of the method. It doesn’t have the same problems that returning Missing.Value has.

That concern would be solvable by adding a new sentinel value for this.

We could simply continue to throw NotSupportedException in the case of a null ref return

This would execute the target method (successfully) and then throw - it’s a behavior that doesn’t have a precedent for this API. I would want to run this through API review.

MethodInfo.Invoke is not equivalent to object result = RefReturningMethod();.

MethodInfo.Invoke tries it’s best to give you a usable result back. That’s why you get System.Reflection.Pointer back for methods that return unmanaged pointers (instead of just throwing and telling you to go away because you can’t box pointer types). It’s a special value that is not what the boxed result of invocation was, but something that lets you reconstruct it.

I thought about this a bit more and I firmly think that NRE is the right choice here.

  1. If I do
object result = RefReturningMethod();

and if the method returns nullptr, I do get NRE (in both C# and VB and I assume in any other language). Regardless of the actual type of the method. - int, object or Missing -

I am dereferencing when I demand a value form a ref returning method. And dereferencing null throws. I do not see why calling via reflection should behave any differently.

  1. It is not uncommon to handle all the stuff in terms of objects when doing something dynamic. I might never need to unbox the value or unbox it far away from the call. In either case figuring when and what went wrong and why I have a boxed Missing.Value flowing around would be hard.

  2. The case is not very different from when I give you a null array and ask for a first element or give a null instance and ask for a field. Would you find it more logical to throw something or return a Missing.Value? Would people think the exception is because of a reflection bug?

The more general TypeReference based API might be able to work with nullptr, since we would be dealing with references. Even then I am not very sure. Probably.

For the value based API the behavior seems clear - the user is asking to obtain a value of a ref-returning method. That implies dereferencing and possible NRE if the method returns nullptr.