Возвращение в метод базового класса возвращает в вызове дочернего класса? - PullRequest
2 голосов
/ 18 января 2012

Я создаю среду C #, в которой (почти) все мои классы будут основаны на одном абстрактном базовом классе. Этот базовый класс содержит некоторые частные свойства, одним из которых является логическое значение Garbage .

В цикле рисования XNA я не хочу, чтобы какие-либо дочерние классы выполняли код в своих соответствующих методах Draw (), если для свойства Garbage базового класса установлено значение true. Я попытался сделать это со следующей реализацией:

Абстрактный базовый класс:

public virtual void Draw(GameTime GameTime, SpriteBatch SpriteBatch)
{
    if (Garbage) return;
}

Унаследованный класс:

public void Draw(GameTime GameTime, SpriteBatch SpriteBatch, Color OverlayColor, float Scale)
{
    base.Draw(GameTime, SpriteBatch);

    //Other code here...
}    

Поскольку метод Draw базового класса вызывается перед фактическим кодом в моем дочернем классе, он попадает в оператор return , который я хотел бы выполнить в вызове Draw () моего дочернего класса. Однако этого не происходит.

Есть ли способ достичь желаемого эффекта, не добавляя слова "if (Garbage) return;" ограничение на вершину метода Draw () каждого унаследованного класса?

Ответы [ 6 ]

5 голосов
/ 18 января 2012

Одна вещь, которую вы могли бы рассмотреть, это иметь два метода.Вы можете иметь свой метод Draw на абстрактной базе, который не переопределяется, а затем определить абстрактный защищенный метод PerformDraw (), который переопределяются вашими наследниками.

Абстрактное базовое рисование выглядит так:

public void Draw(GameTime GameTime, SpriteBatch SpriteBatch)
{
    if (!Garbage) PerformDraw(GameTime, SpriteBatch);
}

Это позволяет вам переопределить поведение при рисовании, но заставляет всех наследников использовать проверку "мусора".

4 голосов
/ 18 января 2012

Нет, через наследование / полиморфизм невозможно достичь того, чего вы хотите.Я хотел бы предложить иметь Entity Manager, который содержит все ваши объекты, которые хотят рисовать, и может через каждый из них произносить что-то с эффектом:

foreach (IEntity entity in _entities)
{
       if(!entity.Garbage)
            entity.Draw(....);
}

Таким образом, если вызывается draw, объект может выполнятьчто он должен делать и мусор перемещается на другой уровень и позволяет ему быть гибким, поэтому если позже вам понадобится добавить еще одно предложение, прежде чем объект сможет нарисовать, вам нужно всего лишь изменить 1 строку кода, а не каждый метод рисования ив основном получить эффект, к которому вы изначально стремились.

3 голосов
/ 19 января 2012

Если это вообще возможно, вы можете рассмотреть Шаблонный шаблон .Пусть основной метод будет таким:

public void Draw(GameTime gameTime, SpriteBatch spriteBatch, Color overlayColor, float scale)
{
    if (Garbage) return;

    DrawMe(gameTime, spriteBatch, overlayColor, scale);
}

protected abstract DrawMe(GameTime gameTime, spriteBatch SpriteBatch, Color overlayColor, float scale);

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

1 голос
/ 19 января 2012

Я думаю, что вы делаете что-то немного в обратном направлении.Ваш наименее перегруженный метод должен вызывать следующий вызов и так далее.

Пример моего метода рисования

public override void Draw(List<string> menuOptions, int currentSelection, MenuType type)
{
    Draw("", menuOptions, currentSelection, type, Color.White, Color.Gray, Color.WhiteSmoke, Color.DimGray);
}

public void Draw(string menuName, List<string> menuOptions, int currentSelection, MenuType type)
{
    Draw(menuName, menuOptions, currentSelection, type, Color.White, Color.Gray, Color.WhiteSmoke, Color.DimGray);
}

public void Draw(string menuName, List<string> menuOptions, int currentSelection, MenuType type, Color foreNorm, Color backNorm, Color foreSelect, Color backSelect)
{
    //Actual Draw
}
1 голос
/ 19 января 2012

Ну, просто пример:

public class BaseClass 
{
   public bool Garbage {get;set}
}

//somewhere you have a collection of all artifacts to draw (children of BaseClass) 
Lis<BaseClass> stuffToDraw = new List<BaseClass){....}

//and somewhere in the framewrok you have a method to draw them  

public void Paint(...)
{
     stuffToDraw.ForEach(stuff=>
     {
         if(stuff.Garbage) return; 
         stuff.Draw(....); //call of overriden virtual method
     });
}

Таким образом, у вас есть одно место, где можно проверить, рисовать артефакт или нет.

Надеюсь, этопомогает.

1 голос
/ 18 января 2012

Если вы хотите, чтобы ваш дочерний класс вызывался по вызову функции в зависимости от ситуации в родительском классе при обратном вызове void, у вас есть следующие варианты:

1) Проверить защищенный / общедоступныйпеременная флага в вашем дочернем методе и затем логика ветвления.AKA

// base class
if (Garbage) _someFlag = true;

// child class

base.Draw();

if(!_someFlag) // Do Stuff

2) Создайте исключение в родительском классе, которое не позволяет выполнять остальную часть функции (при условии, что это соответствует вашей ситуации).

В вашем конкретном случае вы пытаетесь вернуть данные из родительского класса в дочерний класс с помощью метода void.Если бы это был я, я бы сделал что-то вроде этого:

// base class
public bool IsGarbage { get; set; }

// child class

public void Draw()
{
     if(!IsGarbage)
     {
         // Do Stuff
     }
}
...