Статическое наследование членов в С#, как лучше всего?

Каков наилучший способ решить эту проблему?

Статический член один для всех подклассов, и мне нужен другой статический член для подклассов, но с тем же именем, чтобы я мог использовать Vehicle.canDo; это должно дать мне разные массивы в зависимости от того, к какому классу относится экземпляр vechicle.

Я могу просто удалить статику из массива canDo, но все экземпляры одного и того же подкласса всегда должны иметь одинаковые значения в массиве canDo, поэтому нет необходимости иметь массив canDo в каждом экземпляре, это будет большая трата памяти, потому что у меня будет слишком много экземпляров этого класса.

class Vehicle {
    public static List<string> canDo;

    static Vehicle() {
        canDo = new List<string>(); 
        canDo.Add("go");
    }
}

class Plane : Vehicle {
    static Plane() {
        canDo.Add("fly");
    }
}

class Ship : Vehicle {
    static Ship() {
        canDo.Add("sail");
    }
}



class Main {
    static void Main(string[] args) {
        Vehicle plane = new Plane();
        Vehicle ship = new Ship();

        plane.canDo; // Contains (go, fly and sail) i want only (go and fly)
        ship.canDo; // Contains (go, fly and sail) i want only (go and sail)
    }
}

person Mustafa    schedule 03.07.2012    source источник
comment
на мой взгляд, удаление квалификатора 'static' из canDo должно решить эту проблему   -  person Alex    schedule 03.07.2012
comment
Мустафа, я не верю, что этого можно будет добиться, сохраняя атрибут статичным. На самом деле, при использовании static в любом элементе (методе, атрибуте, классе) этот элемент будет иметь только один экземпляр (вроде, на самом деле ) для всего приложения (и это важно, у них будет одинаковый жизненный цикл).   -  person Andre Calil    schedule 03.07.2012
comment
возможный дубликат Is можно ли создать переменную в родительском классе, которая бы инициализировалась один раз для каждого производного типа? хотя формулировка сильно отличается, проблема та же   -  person Rune FS    schedule 03.07.2012


Ответы (4)


Вам нужен экземпляр списка canDo для каждого типа. Таким образом, либо вы можете передать коллекцию через конструктор, либо вы можете иметь статику на уровне подтипа.

Изменить (уточнить):

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

public abstract class Vehicle
{
    protected List<string> canDo;

    protected Vehicle(List<string> canDo)
    {
        this.canDo = canDo;
    }
}

public class Plane : Vehicle
{
    public Plane(List<string> canDo) : base(canDo)
    {
    }
}

Я бы тоже не стал использовать List<string>, а скорее инкапсулировал бы его в класс, который имеет смысл для бизнеса (хотя я понимаю, что это только пример). Чтобы заполнить список canDo, вы можете использовать фабрику или фабричный метод для подтипа.

Есть так много способов сделать это, что вам нужно найти то, что удобно.

Хотя я представил статику в качестве альтернативы (поскольку вы спрашивали об этом), я определенно не стал бы использовать статику для этого сам.

person Eben Roux    schedule 03.07.2012
comment
Разве исходное намерение не заключалось в том, чтобы хранить данные на уровне класса, а не на уровне экземпляра? Если я не ошибаюсь (конечно, правдоподобно), это противоречит цели... - person weberc2; 29.11.2012

Каков наилучший способ решить эту проблему?

Не злоупотребляйте статическими методами для вещей, которые не являются статическими. Просто так.

Static не имеет наследования и НЕ МОЖЕТ иметь какие-либо сценарии наследования.

Вы ведете битву, злоупотребляя функцией — не стоит сражаться. Пожалуйста, изучите правильную ориентацию объекта.

person TomTom    schedule 03.07.2012
comment
Каков «правильный» способ реализации данных на уровне класса (не уровня экземпляра) без повторения кода снова и снова? - person weberc2; 29.11.2012
comment
Не делать этого. Реализовать синглтон, в значительной степени. Ссылка на ЭКЗЕМПЛЯР контейнера, где он вам нужен. Вы можете повторить метод/ссылку, но не данные экземпляра. - person TomTom; 29.11.2012
comment
Почему бы и нет, если это облегчает вашу работу? Я не пишу объектно-ориентированный код ради написания объектно-ориентированного кода — я пишу объектно-ориентированный код, потому что он должен помочь мне хорошо решать проблемы. Если он не может помочь решить проблемы, значит, он не служит своей цели, и я обойдусь без него, чтобы автоматизировать процесс. Для справки, JonSkeet предложил отличное решение аналогичной проблемы здесь: stackoverflow.com/a/13631714/483347 - person weberc2; 29.11.2012
comment
Трюк с умной игрой заключается в том, что если вы не знаете, что делаете, ваша сообразительность ударит вас по заднице через год. Многие новички видят массу вещей проще, а потом начинают звать на помощь. Просто так. Последнее, когда вы пытаетесь работать с данными в динамическом режиме, вы в конечном итоге сталкиваетесь с отражением идиотского дизайна класса. - person TomTom; 29.11.2012
comment
Или вы реализуете действительно хороший дизайн класса, который сэкономит ваше время в будущем. Я не говорю, что все понимаю, я просто отвергаю, потому что это не то, как что-то делается, в качестве окончательного ответа на вопрос, почему что-то не следует делать. - person weberc2; 30.11.2012
comment
Что ж, действительно хороший дизайн класса, игнорирующий ограничения языка, — это кто-то, кто думает, что может сделать настоящий стейк из кобе без мяса. - person TomTom; 30.11.2012
comment
Я не знаю, какое отношение кобе стейк имеет к чему-либо, но лично, если мне нужно обойти недостающую функцию (или антифункцию) языка, и я могу сделать это устойчиво, я это сделаю. Вы можете делать то, что вам нравится. - person weberc2; 30.11.2012

Обратите внимание, что вы также можете скрыть canDo базового класса, используя new:

class Vehicle
{
    public static List<string> canDo = new List<string>() { "go" };   
}

class Plane : Vehicle
{
    public new static List<string> canDo = new List<string>(Vehicle.canDo);
    static Plane()
    {
        canDo.Add("fly");
    }
}
person Eren Ersönmez    schedule 03.07.2012

Для этого вам не нужны статические переменные и конструкторы, просто добавьте базовые конструкторы (что делается по умолчанию, : base() необязательно):

class Vehicle {
    public List<string> canDo;

    Vehicle() {
        canDo = new List<string>(); 
        canDo.Add("go");
    }
}

class Plane : Vehicle {
    Plane() : base() {
        canDo.Add("fly");
    }
}

class Ship : Vehicle {
    Ship() : base() {
        canDo.Add("sail");
    }
}

ОБНОВЛЕНИЕ: на основе комментария @Eben Roux -

public abstract class Vehicle {
    protected static List<string> _canDo;
    protected abstract List<string> getCanDo();
    public List<string> canDo{
        { get {
               var _cando = new List();
               _cando.AddRange(Vehicle._canDo);
               _cando.AddRange(this.getCanDo());
               return _cando;
              }
        }
    }
    static Vehicle() {
        _canDo = new List<string>(); 
        _canDo.Add("go");
    }
}

class Ship : Vehicle {
    protected static List<string> childCanDo;
    protected override getCanDo(){
        return Ship.childCanDo;
    }
    static Ship() {
        childCanDo.Add("sail");
    }
}
person Tisho    schedule 03.07.2012
comment
ОП был обеспокоен тем фактом, что каждый экземпляр, скажем, корабля будет иметь свою собственную коллекцию canDo и что она фактически дублируется для каждого экземпляра (надеюсь, это имеет смысл). В этом нет ничего плохого, если у вас не будет много экземпляров; в противном случае состояние можно было бы просто разделить, каким-то образом внедрив коллекцию canDo или извлекая ее. - person Eben Roux; 03.07.2012
comment
@EbenRoux - спасибо за объяснение. Я пропустил этот момент. Итак, вы все равно можете сохранить статический базовый список и объединить его с дочерними классами... Я немного обновил ответ... Я не тестировал код, но надеюсь, что идея ясна.. - person Tisho; 03.07.2012
comment
... Но вся идея наследования здесь исчезла ... Как сказано в других ответах, статике здесь нет места. - person Tisho; 03.07.2012
comment
Согласен :) --- тем не менее, я считаю, что статика имеет место быть, но она требует тщательного рассмотрения и проектирования. - person Eben Roux; 03.07.2012