9

我在下面的代码中简化并重现了我的问题。我收到的错误是:参数 1:无法从 'System.Collections.ObjectModel.Collection' 转换为 'System.Collections.ObjectModel.Collection

导致此问题的设计决策的一些背景:我创建了一个用于处理“IFruit”的 Web 服务,但由于 SOAP 和端点绑定的性质,据我所知,我创建了具有 IFruit 显式实现的方法。在业务层上,为每个水果的具体实现创建一个单独的方法首先会导致大量重复代码,其次业务和服务层耦合得足够紧密,以至于以后在 Web 服务中接受新的 IFruit 类型也需要更改我的代码在业务层中(添加另一个冗余代码副本)。这种设计是我过去使用 Java 成功实现的设计,但 C# 接口似乎完全不同,足以让我失望。请指教。

public interface IFruit{
    public string TakeBite();
}

public Apple : IFruit{
    public string TakeBite(){
        return "tasty bite of apple";
    }
}

public void EatFruit(Collection<IFruit> fruits){
    foreach(var fruit in fruits){
        Console.WriteLine(fruit.TakeBite());
    }
}

public void EatApples(Collection<Apple> apples){
    this.EatFruit(apples);
}
4

4 回答 4

10

尝试改变你EatFruit的接受方式IEnumerable<IFruit>

public void EatFruit(IEnumerable<IFruit> fruits)
{
    foreach (var fruit in fruits)
    {
        Console.WriteLine(fruit.TakeBite());
    }
}

该接口IEnumerable<out T>支持协方差,因为它用out修饰符标记。 Collection<T>没有标记这样的修饰符。

于 2012-07-06T18:00:04.930 回答
1

这叫做协方差。
但是,使用可变集合是不可能的。

否则,EatFruit可以写

fruits.Add(new Orange());

.Net 4 确实支持纯接口的协方差,因此您可以将其更改为IEnumerable<IFruit>它会起作用。

于 2012-07-06T17:58:06.310 回答
1

简单的解决方案:

public void EatApples(Collection<Apple> apples){
     this.EatFruit(
          new Collection<IFruit>(
              apples.Cast<IFruit>()
          )
     );
}

更好的解决方案:使用 C# 4 中引入的协方差:参见Kevin的回答

于 2012-07-06T18:16:56.077 回答
0

除了使用 IEnumerable 之外,您还可以键入检查集合(有点可怕,但它应该可以工作):

public void EatApples(Collection<IFruit> fruit)
    var col = new Collection<IFruit>();

    fruit.Where(x => x is Apple).ToList().ForEach(x => col.Add(x));

    this.EatFruit(col);
}

虽然我会改用 IEnumerable - 如果你不能重构,这只是一个选项:P

(它和你做的一样安全!)

于 2012-07-06T18:09:59.700 回答