我试图创建一个隐式转换,它允许我使用linq结果直接返回MyCollection
。
public class MyCollection : ICollection<MyType>
{
private List<MyType> _list = new List<MyType>();
public MyCollection(IEnumerable<MyType> collection)
{
_list = new List<MyType>(collection);
}
public static implicit operator MyCollection(IEnumerable<MyType> collection)
{
return new MyCollection(collection);
}
// collection methods excluded for brevity
public MyCollection Filter(string filter)
{
return _list.Where(obj => obj.Filter.Equals(filter)); // cannot implicitly convert
}
}
我以前没有试过使用隐式用户定义的转换,我做错了什么?
最佳答案
当类型转换自或类型转换为接口类型时,不允许使用implicit
。(如果一种类型是从另一种类型派生的,则也不允许使用这些类型,因此,可以像以前一样使用barobject
)。实际上,在这种情况下也不允许explicit
。根据ECMA-364第17.9.3节:
只有在以下所有条件均为真时,类或结构才允许声明从源类型S
到目标类型T
的转换,其中S0
和T0
是从?
和S
中删除尾部T
修饰符(如果有)所产生的类型:S0
和T0
是不同的类型。S0
或T0
是运算符声明发生的类或结构类型。S0
和T0
都不是接口类型。
不包括用户定义的转换,转换不存在于S
到T
或从T
到S
。
您正在破坏第三个规则(接口类型)和第四个规则(因为已经存在从MyCollection
到IEnumerable<MyType>
的非用户定义转换)。
如果允许的话,我还是建议不要这样做。
只有当效果非常明显时才应该使用隐式类型转换(对有合理语言知识的人来说):非常明显的是long x = 3 + 5
在castingint
到long
中的作用,非常明显的是object x = "abc"
在castingstring
到object
中的作用。
除非您使用的implicit
类似于“显而易见”的级别,否则这是一个坏主意。
特别是,通常隐式类型转换不应在相反的方向上隐式,而应在一个方向上隐式(在大多数内置情况下为“加宽”方向),在相反的方向上显式(为“缩小”方向)。因为您已经有了一个从MyCollection
到IEnumerable<MyCollection>
的隐式转换,所以在相反的方向有一个隐式转换几乎是一个坏主意。
更一般地说,既然您正在讨论linq的使用,那么使用可扩展的ToMyCollection()
方法会带来更大的好处,因为接下来您将遵循ToArray()
、ToList()
等linq惯例:
public static class MyCollectionExtensions
{
public static MyCollection ToMyCollection(this IEnumerable<MyType> collection)
{
return collection as MyCollection ?? new MyCollection(collection);
}
}
注意,我测试的是集合已经
MyCollection
的情况,以避免浪费的重复构造。您可能希望也可能不希望处理List<MyType>
的情况,特别是在使用直接将其分配给_list
的内部构造函数时。但是,在执行此操作之前,需要考虑允许的锯齿效果。如果知道别名不会导致问题(类仅在内部使用,而别名已知不是问题,或者别名不会影响
MyCollection
的使用,或者别名实际上是可取的),则这是一个非常有用的技巧。如果有疑问,那就让这个方法变得更安全。