Nano Hash - криптовалюты, майнинг, программирование

Как получить доступ к свойствам объекта List ‹Interface›, когда его класс унаследован от интерфейса?

Хорошо, вот в чем проблема. У меня есть интерфейс IBook, который включает свойство Name. Есть два класса, которые наследуются от IBook и добавляют собственное свойство Genre. Я хочу создать словарь или список и добавить туда всевозможные книги и получить к ним доступ по строке и их свойствам, поэтому я сделал его словарём. В этом примере я могу получить доступ к книгам ["LOTR"]. Имя, но не к книгам ["LOTR"]. Жанр, вероятно потому, что имя является свойством интерфейса IBook, а жанр является свойством класса, наследуемого от IBook.

Можно ли заставить словарь или список работать с типом интерфейса и по-прежнему иметь доступ ко всем свойствам наследующего класса, или мне следует использовать массив или что-то в этом роде?

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();
    }
}
}

  • если у всех есть имя и жанр, почему бы вам тогда не добавить жанр в интерфейс? Вы можете получить доступ ко всем свойствам, которых нет в интерфейсе, если вы приведете свой (books["LOTR"] as FantasyBook).Genre 13.12.2019
  • Можно ли заставить словарь или список работать с типом интерфейса и по-прежнему иметь доступ ко всем свойствам наследующего класса, а это невозможно. или я должен использовать массив или что-то в этом роде? проблема не в коллекции, содержащей IBook, поэтому повторное использование массива ничего не решит. решение вашей проблемы можно просто решить, сделав Genre частью IBook определения, поскольку это имеет смысл. почему вы вообще не учли это? в чем заключалась идея дизайна? 13.12.2019
  • Вы можете ввести базовый абстрактный класс, например BaseBook со свойством Name (или добавить его в интерфейс), а затем привести значение словаря к этому типу для доступа к Name 13.12.2019
  • Это просто пример ситуации в другом проекте, над которым я работаю. Таким образом, существует множество различных типов наследующих классов, которые добавляют разные типы свойств. 13.12.2019
  • Досадно, что вы назначаете интерфейсы по жанрам и имеете свойство Genre. Плохо пахнет. 13.12.2019
  • Чарльз, это почти то же самое, что я пытаюсь здесь сделать. Можно ли получить доступ к свойствам наследующего класса с помощью только строки LOTR, не зная типа фактического класса? 13.12.2019
  • Вы можете протестировать books["LOTR"] is FantasyBook, а затем разыграть его. Но это, вероятно, ужасная идея, очень анти-объектно-ориентированная, особенно в свете фундаментального недостатка объектно-ориентированного моделирования, на который указал @RamblinRose. 13.12.2019
  • Кстати, взгляните на авто свойства. Этот вопрос пахнет домашним заданием, поставленным профессором, изучившим C # в 2003 году. 13.12.2019
  • Как я уже сказал, это всего лишь пример (возможно, плохой) проблемы, с которой я столкнулся с другим проектом с другим интерфейсом, классами и множеством свойств. Возможно, для решения этой проблемы нужен другой подход. Спасибо за подсказку auto-property, воспользуюсь этим! 13.12.2019

Ответы:


1

Комментарии в значительной степени относятся к делу - вы не можете этого сделать, поскольку компилятор проверит доступные элементы на IBook (поскольку вы его объявили) и не позволит вам выстрелить себе в ногу, пытаясь получить доступ к свойству, которое там не определено. Это проверка статического типа.

Но давайте на секунду представим, что вам наплевать на безопасность типов и производительность. Оказывается, тогда у вас есть выбор. Ну, вроде как ... вам все равно придется отказаться от вашего конкретного 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();
    }

Ознакомьтесь с динамическим для дальнейшее чтение. Это связано с рисками, описанными в моем примере, а также со снижением производительности. Само по себе это неплохо, просто нужно принимать в меру.

13.12.2019
  • Ответ Тимура должен работать. Большое спасибо! Я понимаю, что мне нужно быть очень осторожным с динамикой, чтобы не создавать проблемы с ошибками во время выполнения. 13.12.2019

  • 2

    Альтернативный подход - добавить еще один уровень интерфейса с 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();
        }
    }
    
    13.12.2019
    Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..