I'd like to automatically wrap a value in a generic container on return (I am aware that this is not always desirable, but it makes sense for my case). For example, I'd like to write:
public static Wrapper<string> Load() {
return "";
}
I'm able to do this by adding the following to my Wrapper class:
public static implicit operator Wrapper<T>(T val) {
return new Wrapper<T>(val);
}
Unfortunately, this fails when I attempt to convert an IEnumerable
, complete code here (and at ideone):
public class Test {
public static void Main() {
string x = "";
Wrapper<string> xx = x;
string[] y = new[] { "" };
Wrapper<string[]> yy = y;
IEnumerable<string> z = new[] { "" };
Wrapper<IEnumerable<string>> zz = z; // (!)
}
}
public sealed class Wrapper<T> {
private readonly object _value;
public Wrapper(T value) {
this._value = value;
}
public static implicit operator Wrapper<T>(T val) { return new Wrapper<T>(val); }
}
The compilation error I get is:
Cannot implicitly convert type 'System.Collections.Generic.IEnumerable<string>' to '...Wrapper<System.Collections.Generic.IEnumerable<string>>'
What exactly is going on, and how can I fix it?
The reason is part of the C# spec, as noted in this answer:
A class or struct is permitted to declare a conversion from a source type S to a target type T provided all of the following are true:
- ...
- Neither S nor T is
object
or an interface-type.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.
Source
Your implicit conversion works when used differently, like in the following code:
using System;
using System.Collections.Generic;
public class Wrapper<T>
{
public T Val { get; private set; }
public Wrapper(T val)
{
Val = val;
}
public static implicit operator Wrapper<T>(T val)
{
return new Wrapper<T>(val);
}
}
public class Test
{
public static Wrapper<IEnumerable<int>> GetIt()
{
// The array is typed as int[], not IEnumerable<int>, so the
// implicit operator can be used.
return new int[] { 1, 2, 3 };
}
public static void Main()
{
// Prints 1, 2, 3
foreach (var i in GetIt().Val)
{
Console.WriteLine(i);
}
}
}
The specific issue you're running into is because you store your array in a IEnumerable<string>
local variable before returning it. It's the type of the variable passed into the implicit operator that matters: because the source type S
is IEnumerable<int>
on your local variable, the operator can't be used. int[]
isn't an interface, so it works.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With