将泛型隐式转换为包装器
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.
您的隐式转换在以不同方式使用时有效,如以下代码:
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>
局部变量中。重要的是传递给隐式运算符的变量类型:因为本地变量的源类型 S
是 IEnumerable<int>
,所以不能使用该运算符。 int[]
不是接口,所以可以。
我想在 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.
您的隐式转换在以不同方式使用时有效,如以下代码:
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>
局部变量中。重要的是传递给隐式运算符的变量类型:因为本地变量的源类型 S
是 IEnumerable<int>
,所以不能使用该运算符。 int[]
不是接口,所以可以。