我试图创建一个隐式转换,它允许我使用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的转换,其中S0T0
是从?S中删除尾部T修饰符(如果有)所产生的类型:
S0T0是不同的类型。
S0T0是运算符声明发生的类或结构类型。
S0T0都不是接口类型。
不包括用户定义的转换,转换不存在于ST或从TS
您正在破坏第三个规则(接口类型)和第四个规则(因为已经存在从MyCollectionIEnumerable<MyType>的非用户定义转换)。
如果允许的话,我还是建议不要这样做。
只有当效果非常明显时才应该使用隐式类型转换(对有合理语言知识的人来说):非常明显的是long x = 3 + 5在castingintlong中的作用,非常明显的是object x = "abc"在castingstringobject中的作用。
除非您使用的implicit类似于“显而易见”的级别,否则这是一个坏主意。
特别是,通常隐式类型转换不应在相反的方向上隐式,而应在一个方向上隐式(在大多数内置情况下为“加宽”方向),在相反的方向上显式(为“缩小”方向)。因为您已经有了一个从MyCollectionIEnumerable<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的使用,或者别名实际上是可取的),则这是一个非常有用的技巧。如果有疑问,那就让这个方法变得更安全。

07-24 19:01
查看更多