将泛型隐式转换为包装器

Implicitly converting a generic to a wrapper

我想在 return 上的通用容器中自动包装一个值(我知道这并不总是可取的,但对我的情况来说很有意义)。例如,我想写:

public static Wrapper<string> Load() {
    return "";
}

我可以通过将以下内容添加到我的 Wrapper class 来做到这一点:

public static implicit operator Wrapper<T>(T val) {
    return new Wrapper<T>(val); 
}

不幸的是,当我尝试转换 IEnumerable 时失败了,完整代码在这里(和 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); }
}

我得到的编译错误是:

Cannot implicitly convert type 'System.Collections.Generic.IEnumerable<string>' to '...Wrapper<System.Collections.Generic.IEnumerable<string>>'

究竟是怎么回事,我该如何解决?

原因是 C# 规范的一部分,如 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.

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

您的隐式转换在以不同方式使用时有效,如以下代码:

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);
        }
    }
}

您 运行 遇到的具体问题是因为您在返回数组之前将其存储在 IEnumerable<string> 局部变量中。重要的是传递给隐式运算符的变量类型:因为本地变量的源类型 SIEnumerable<int>,所以不能使用该运算符。 int[] 不是接口,所以可以。