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>>'
究竟发生了什么,我该如何解决?
原因是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>在返回之前将数组存储在局部变量中.这是传递到了重要的隐性操作变量的类型:因为源类型S是IEnumerable<int>在局部变量,操作者不能使用.int[]不是一个接口,所以它的工作原理.