简体   繁体   English

如何访问列表<Interface>从接口继承类时的对象属性?

[英]How to access List<Interface> object properties when it's class is inherited from interface?

Ok, so here's the problem.好的,问题来了。 I have an interface IBook, which includes property Name.我有一个接口 IBook,其中包括属性名称。 There is two classes which inherit from the IBook and add their own property Genre.有两个类继承自 IBook 并添加了自己的属性 Genre。 I wanna create a Dictionary or a List and add all kinds of books there and access them by string and their properties so I made it Dictionary.我想创建一个字典或一个列表,并在那里添加各种书籍并通过字符串及其属性访问它们,所以我制作了字典。 In the example, I can access books["LOTR"].Name but not books["LOTR"].Genre, propably because Name is property of the IBook interface but Genre is property of the class that inherits from the IBook.在示例中,我可以访问 books["LOTR"].Name 但不能访问 books["LOTR"].Genre,这可能是因为 Name 是 IBook 接口的属性,而 Genre 是从 IBook 继承的类的属性。

Is it possible to make the Dictionary or List work with the interface type and still be able to access all the inheriting class properties as well, or should I use an array or something?是否可以使 Dictionary 或 List 与接口类型一起使用并且仍然能够访问所有继承类属性,还是应该使用数组或其他东西?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp124
{
interface IBook
{
    string Name { get; set; }
}

public class FantasyBook:IBook
{
    string name;
    string genre;

    public string Name
    {
        get { return name; }
        set { name = value; }
    }
    public string Genre
    {
        get { return genre; }
        set { genre = value; }
    }
}
public class HorrorBook : IBook
{
    string name;
    string genre;

    public string Name
    {
        get { return name; }
        set { name = value; }
    }
    public string Genre
    {
        get { return genre; }
        set { genre = value; }
    }
}
class Program
{
    static void Main(string[] args)
    {
        FantasyBook LordOfTheRings = new FantasyBook();
        HorrorBook Frankenstein = new HorrorBook();
        Dictionary<string, IBook> books = new Dictionary<string, 
IBook>();

        books.Add("LOTR", LordOfTheRings);
        books.Add("Frankenstein", Frankenstein);
        books["LOTR"].Name = "Lord Of The Rings";
        books["LOTR"].Genre = "Fantasy";
        Console.ReadLine();
    }
}
}

An alternative approach is to add another layer of interface with Genre and use pattern matching for accessing the properties:另一种方法是添加另一层与Genre的接口,并使用模式匹配来访问属性:

interface IBook
{
    string Name { get; set; }
}

interface IBookWithGenre : IBook
{
    string Genre { get; set; }
}

public class FantasyBook : IBookWithGenre
{
    public string Name { get; set; }
    public string Genre { get; set; }
}
public class HorrorBook : IBookWithGenre
{
    public string Name { get; set; }
    public string Genre { get; set; }
}

public class SimpleBook : IBook
{
    public string Name { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        FantasyBook LordOfTheRings = new FantasyBook();
        HorrorBook Frankenstein = new HorrorBook();
        SimpleBook abook = new SimpleBook();
        var books = new Dictionary<string, IBook>
        {
            { "LOTR", LordOfTheRings },
            { "Frankenstein", Frankenstein },
            { "Simple", abook },
        };
        books["LOTR"].Name = "Lord Of The Rings";
        if (books["LOTR"] is IBookWithGenre withGenre)
        {
            withGenre.Genre = "Fantasy";
        }
        Console.ReadLine();
    }
}

The comments are pretty much on point - you cannot do that as the compiler will examine available members on the IBook (since you declared it) and will not let you shoot yourself in the foot by trying to access a property that's not defined there.评论非常重要 - 您不能这样做,因为编译器将检查IBook上的可用成员(因为您声明了它),并且不会让您尝试访问未在其中定义的属性,从而使自己陷入IBook This is static type checking .这是静态类型检查

But let's for a second imagine you don't care about type safety and performance.但是让我们再想象一下你不关心类型安全和性能。 It turns out, you have an option then.事实证明,你有一个选择。 Well, sort of...as you will still have to give up your specific IBook for dynamic嗯,有点......因为你仍然需要放弃你的特定IBook以获得dynamic

interface IBook {
    string Name { get; set; }
}

public class FantasyBook : IBook
{
    public string Name { get; set; }
    public string Genre { get; set; }
}
public class HorrorBook : IBook
{
    public string Name {get;set;}
    public string Genre {get;set;}
}

public class BadaBook : IBook // so I added this new class that does not implement Genre to illustrate a point
{
    public string Name { get; set; }
}
static void Main(string[] args)
    {
        var LordOfTheRings = new FantasyBook();
        var Frankenstein = new HorrorBook();
        var Badaboom = new BadaBook();
        Dictionary<string, dynamic> books = new Dictionary<string, dynamic>();

        books.Add("LOTR", LordOfTheRings);
        books.Add("Frankenstein", Frankenstein);
        books.Add("Badaboom", Badaboom);
        books["LOTR"].Name = "Lord Of The Rings";
        books["LOTR"].Genre = "Fantasy";
        books["Badaboom"].Name = "We can easily assign Name as it is defined. No problem here";
        books["Badaboom"].Genre = "But we will miserably fail here"; // RuntimeBinderException: 'UserQuery.BadaBook' does not contain a definition for 'Genre'

        Console.ReadLine();
    }

Check out dynamic for further reading.查看动态以进一步阅读。 It comes with the risks outlined in my example as well as performance penalties.它伴随着我的示例中概述的风险以及性能损失。 It's not bad per se, it just needs to be taken in moderation.它本身并不坏,只是需要适度服用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM