将泛型隐式转换为包装器

mk.*_*mk. 6 c# generics implicit-conversion

我想在返回时自动将值包装在通用容器中(我知道这并不总是可取的,但对我的情况来说这是有道理的).例如,我想写:

public static Wrapper<string> Load() {
    return "";
}
Run Code Online (Sandbox Code Playgroud)

我可以通过在Wrapper类中添加以下内容来完成此操作:

public static implicit operator Wrapper<T>(T val) {
    return new Wrapper<T>(val); 
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,当我尝试在IEnumerable这里(以及在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); }
}
Run Code Online (Sandbox Code Playgroud)

我得到的编译错误是:

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

究竟发生了什么,我该如何解决?

31e*_*384 5

原因是C#规范的一部分,如本答案中所述:

如果满足以下所有条件,则允许类或结构声明从源类型S到目标类型T的转换:

  • ...
  • S和T都不是object接口类型.

不允许用户定义的转换从接口类型转换或转换为 接口类型.特别是,此限制确保在转换为接口类型时不会发生用户定义的转换,并且只有在转换 的对象实际实现指定的接口类型时,才能成功转换为 接口类型.

资源

隐式转换在使用时有所不同,如下面的代码所示:

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

您遇到的具体问题是因为您IEnumerable<string>在返回之前将数组存储在局部变量中.这是传递到了重要的隐性操作变量的类型:因为源类型SIEnumerable<int>在局部变量,操作者不能使用.int[]不是一个接口,所以它的工作原理.

  • "允许类或结构声明从源类型`S`到目标类型`T`的转换[...]既不是`S`也不是`T`都是对象或接口类型." 在repro的情况下,`S`是`IEnumerable <int>`.这是错的吗?(评论我回复看起来已被删除,抱歉缺乏上下文.) (2认同)