Skip to content
This repository has been archived by the owner on Dec 14, 2018. It is now read-only.

Issue with implicit conversion of ActionResult<T> #7981

Closed
NatMarchand opened this issue Jun 28, 2018 · 5 comments
Closed

Issue with implicit conversion of ActionResult<T> #7981

NatMarchand opened this issue Jun 28, 2018 · 5 comments

Comments

@NatMarchand
Copy link

NatMarchand commented Jun 28, 2018

I'm encountering a bug with ASPNet Core 2.1 whether it is with .Net Framework or .Net Core.
When using the implicit conversion of ActionResult, this works :

var t1 = "toto";
ActionResult<string> r1 = t1;

This works :

var t2 = new List<string>();
ActionResult<List<string>> r2 = t2;

This does not compile (but according to me, it should) :

IEnumerable t3 = new List<string>();
ActionResult<IEnumerable> r3 = t3;

However, this compile :

ActionResult<T> AsActionResult<T>(T t) => t;
IEnumerable t3 = new List<string>();
ActionResult<IEnumerable> r3 = AsActionResult(t3);

It seems that the implicit conversion does not work with interfaces.
Not sure if this bug belongs to this repo, or another ?

@khellang
Copy link
Contributor

This is a C# language restriction. From the C# 6 spec:

For a given source type S and target type T, if S or T are nullable types, let S0 and T0 refer to their underlying types, otherwise S0 and T0 are equal to S and T respectively. A class or struct is permitted to declare a conversion from a source type S to a target type T only if all of the following are true:

  • S0 and T0 are different types.
  • Either S0 or T0 is the class or struct type in which the operator declaration takes place.
  • Neither S0 nor T0 is an interface_type.
  • Excluding user-defined conversions, a conversion does not exist from S to T or from T to S.

And

User-defined conversions are not allowed to convert from or to interface_types. In particular, this restriction ensures that no user-defined transformations occur when converting to an interface_type, and that a conversion to an interface_type succeeds only if the object being converted actually implements the specified interface_type.

[emphasis added]

@NatMarchand
Copy link
Author

Oh, I see. What's really disturbing is that such a conversion works when using the generic method when T is the interface type:

public ActionResult<T> AsActionResult<T>(T t)
{
    return t;
}

@pranavkm
Copy link
Contributor

The type being returned, not T, is the key here. For instance, this works:

var returnedValue = new List<string>();
ActionResult<IEnumerable<string>> r = returnedValue;

Unfortunately, there's not much we could do here since it's a language restriction. For IEnumerable<> instances, calling ToList on the result would be the way to go. For other interface types, you may consider invoking the ActionResult<T> ctor e.g.

var returnedValue = new Enumerable.Empty<string>();
var r = new ActionResult<IEnumerable<string>>(returnedValue);

@bragma
Copy link

bragma commented Oct 23, 2018

Pardon me for reopening a closed issue, but wouldn't the suggested workaround to use "ToList" cause an overhead?

@pranavkm
Copy link
Contributor

@bragma as a general guidance, I'd recommend profiling your application if you think a particular piece of code has a performance overhead. It's difficult to make a blanket statement that says doing ToList has a noticeable overhead. In addition, returning a iterator has known issues: #5083 (comment)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants