使用yield return返回从基类型继承的对象

时间:2009-10-29 13:25:50

标签: c# generics collections

我有一个名为Media的基类,有两个继承自它的类,PhotoVideo。我正在尝试为媒体基类创建一个集合来保存这些照片和视频对象。所以我创建了一个MediaList类,如下所示:

public class MediaList: ICollection<Media>
{
    private readonly XElement _mediaElement;

    public MediaList(XElement mediaElement)
    {
        _mediaElement = mediaElement;            
    }

    public IEnumerator<Media> GetEnumerator()
    {
        foreach (XElement element in _mediaElement.Elements())
        {
            Media media;
            switch (element.Name.LocalName)
            {
                case "video":
                    media = new Video(element);
                    break;
                case "photo":
                    media = new Photo(element);
                    break;
                default:
                    media = null;
                    break;
            }
            yield return media;
        }
    }

    //Rest of ICollection Implementation
}

当我迭代列表时,我得到以下异常:

值“Tool.Photo”不是“Tool.Video”类型,不能在此通用集合中使用。

如果我返回一个Media对象,为什么要抛出异常?有没有更好的方法来解决这个问题?

4 个答案:

答案 0 :(得分:3)

试试这个......

class Program
{
    static void Main(string[] args)
    {
        var array = new string[] { "video", "photo", "hurf", "photo" };
        var ml = new MediaList(array);
        foreach(var element in ml)
            Console.WriteLine(element.GetType().Name);
        Console.Read();
    }
}

public class Media { }
public class Video : Media { }
public class Photo : Media { }

public class MediaList
{
    private string[] elements;
    public MediaList(string[] elements) { this.elements = elements; }
    public IEnumerator<Media> GetEnumerator()
    {
        foreach (string s in elements)
            switch (s)
            {
                case "video":
                    yield return new Video();
                    break;
                case "photo":
                    yield return new Photo();
                    break;
            }
    }
}

您可以将其打入控制台应用程序进行测试。

注意几件不同的事情。 首先,你永远不会产生返回null。这与您的问题没有任何关系,但是没有人希望枚举返回null并且稍后会引起您的问题。 第二次,我不是在投我的回报。所有转换都是隐式的或由编译器处理,因此我不需要这样做。 第三,这会编译并运行,原始代码也是如此。您的问题正在其他地方发生,因为您会发现将此代码放入控制台应用程序并进行测试。

答案 1 :(得分:2)

你的错误在别的地方。你写的内容很好,只要Video和Photo都继承Media。也许你正试图在其他地方错误地投射它。

答案 2 :(得分:1)

不应该输入带有yield return的方法来返回IEnumerable<Media>,而不是IEnumerator<Media>吗?

但更基本的是,这种模式给我带来了难闻的气味。每次在此“集合”上使用foreach时,您将在Photo列表中创建(实例化)每个Video_mediaElement.Elements()对象的新实例。这真的是你想要的吗?

答案 3 :(得分:0)

您似乎正在尝试将Media个实例添加到Video集合中,并且它会因为其中一个或多个是Photo而爆炸 - 您正在尝试将照片添加到视频集。错误发生在客户端代码中,而不是生成的枚举器中。