у c # есть метод родительского класса, использующий переменную подкласса - PullRequest
0 голосов
/ 09 ноября 2018

Я столкнулся с проблемой, ставя под сомнение мою веру в ООП. Пожалуйста, дайте мне знать, как, если это возможно:

У меня есть родительский класс со Статическим списком (для отслеживания всех созданных объектов, главным образом по причинам UI DataGrid) и метод, ссылающийся на этот список. Нечто подобное

abstract class Animal
{
    public static List<Animal> objList;
    public String Name;

    public Animal(String Name)
    {
        this.Name = Name;
        objList.Add(this);
    }

    public virtual void delete(int i)
    {
        objList.RemoveAt(i);
    }

теперь у меня есть дочерний класс со статическим списком (то же имя, то же назначение, только другой класс), но для того, чтобы метод ссылался на child.list, я должен переписать метод. вот так

class Cat : Animal
{
    public static List<Cat> objList;

    public Cat(String Name) : base(Name)
    {

    }

    //whould it be possible to ommit this method?
    public override void delete(int i)
    {
        objList.RemoveAt(i);
    }
}

Это не может быть лучшим способом. Если бы у меня было 5 детей, все они вставили бы одну и ту же часть кода. Должен быть способ, которым метод родительского класса «delete», если вызывается из дочернего объекта, удаляет его из дочернего списка, а не из родительского списка.

Ответы [ 2 ]

0 голосов
/ 09 ноября 2018

Коллекция не принадлежит базовому классу и, разумеется, не принадлежит ни к каким производным классам.

К сожалению, вы не показываете, как используется ваш List<Animal>, поэтому его трудно показатьосмысленный ответ без вывода поведения, которого вы, возможно, не желаете.

Но если вы настаиваете, вам нужно иметь только одну коллекцию , чтобы содержать всех животных и объявить статическое свойство, которое фильтрует оригиналКоллекция по типу в каждом подклассе.

public abstract class Animal
{
    // this is the _only_ field that should contain
    // a list of all the animals.
    protected static readonly List<Animal> animals = new List<Animal>();

    // Expose a read-only wrapper as public
    public static IReadOnlyList<Animal> AllAnimals => animals.AsReadOnly();

    protected Animal(string color)
    {
        animals.Add(this);
        this.Color = color;
    }
    public string Color { get; }

    public void RemoveMe()
    {
        int index = animals.IndexOf(this);
        if (index >= 0)
        {
            animals.RemoveAt(index);
        }
    }
}    

public class Cat : Animal
{
    public static IReadOnlyList<Cat> AllCats => animals.OfType<Cat>().ToList().AsReadOnly();
    public Cat(string name, string color) : base(color)
    {
        this.Name = name;
    }
    public string Name { get; }
}

public class Fish : Animal
{
    public static IReadOnlyList<Fish> AllFish => animals.OfType<Fish>().ToList().AsReadOnly();
    public Fish(string color) : base(color)
    {
    }
}

static class Program
{
    static void Main(string[] args)
    {
        var cat1 = new Cat("Whiskers", "Tabby");
        var fish1 = new Fish("Striped");
        var cat2 = new Cat("Snoflake", "White");
        var cat3 = new Cat("Midnight", "Black");

        cat2.RemoveMe();

        // list all remaining cats below
        foreach (var cat in Cat.AllCats)
        {
            Debug.WriteLine($"{cat.Name} is a {cat.Color} cat.");
        }
        // Result in Output:
        //Whiskers is a Tabby cat.
        //Midnight is a Black cat.

    }
}
0 голосов
/ 09 ноября 2018

Статические свойства и методы не могут быть переопределены ООП, хотя они могут быть скрыты.

public class Parent : IDisposable
{
    private static List<Parent> objList = new List<Parent>();
    private static IReadOnlyList<Parent> readOnlyList = new ReadOnlyCollection<Parent>(objList);
    public static IEnumerable<Parent> Instances { get { return readOnlyList; } }

    private bool _isDisposed = false;
    public bool IsDisposed {  get { return _isDisposed;  } }

    public Parent()
    {
        objList.Add(this);
    }

    public void Dispose()
    {
        OnDispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void OnDispose(bool disposing)
    {
        if(disposing) { objList.Remove(this); }
        _isDisposed = true;
    }
}

public class Child : Parent
{
    private static IEnumerable<Child> _instances = Parent.Instances.OfType<Child>();
    public new static IEnumerable<Child> Instances { get { return _instances; }}

    public Child() : base()
    {

    }
}

Теперь, если вы хотите удалить i-й элемент из списка, просто используйте команду Parent.Instances (i) .Dispose ();

Вы также можете удалить i-й экземпляр Child, выполнив Child.Instances (i) .Dispose ()

Редактировать: Финализатор удален из Parent, как предлагается в комментариях ниже.

Edit2: Упрощенное выражение LINQ в классе Child для использования .OfType (), как предлагается в комментариях.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...