C #: возможно не реализовать защищенный внутренний реферат на абстрактном классе? - PullRequest
4 голосов
/ 11 ноября 2010

что мне нужно изменить в моей абстрактной базе, чтобы реализации не должны были реализовывать ОБА методы, когда в любом заданном сценарии нужен только один?Мой пример:

internal abstract class BaseBar<T> where T : BaseThing
{
    protected internal abstract T DataFromXmlElements(IEnumerable<XmlNode> nodes);
    protected internal abstract T DataFromXmlElements(IEnumerable<XmlNode> nodes, string[] fieldNames);
}

class FooBarMapper : BaseBar<FooData>
{
    protected internal override SforceObjectValueData DataObjectFromXmlElements(IEnumerable<XmlNode> nodes)
    {
        throw new NotImplementedException();
    }

    protected internal override FooData DataFromXmlElements(IEnumerable<XmlNode> nodes, string[] fieldNames)
    {
        FooData o = new FooData
        {
            bar1 = bar1,
            bar2 = bar2
        };
        return o;
    }
}

Приветствия.

edit: Дизайн странный / плохой / глупый Я знаю ... Я работаю с устаревшим кодом, и время не на моей сторонепрямо сейчас для рефакторинга.Я пытаюсь добавить второй метод с массивом строк.

Ответы [ 9 ]

3 голосов
/ 11 ноября 2010

Может, у тебя сработает?

internal abstract class BaseBar<T> where T : BaseThing
{
    protected internal abstract T DataFromXmlElements(IEnumerable<XmlNode> nodes, params string[] fieldNames);
}
2 голосов
/ 10 октября 2012

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

1 голос
/ 11 ноября 2010

Либо виртуальные реализации по умолчанию, как сказал Колин Маккей, либо используйте интерфейсы и явную реализацию, чтобы остановить внешние методы.

internal interface IBaseBar1<T> where T : BaseThing
{
    T DataFromXmlElements(IEnumerable<XmlNode> nodes);
}

interface IBaseBar2<T> where T : BaseThing
{
    T DataFromXmlElements(IEnumerable<XmlNode> nodes, string[] fieldNames);
}

class FooBarMapper : IBaseBar2<FooData>
{
    FooData IBaseBar2<FooData>.DataFromXmlElements(IEnumerable<XmlNode> nodes, string[] fieldNames)
    {
        FooData o = new FooData
        {
            bar1 = bar1,
            bar2 = bar2
        };
        return o;
    }
}
1 голос
/ 11 ноября 2010

Не возможно.

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

Наконец, вы бы извлекли рабочий класс из ЛИБО абстрагированных классов и таким образом реализовали бы соответствующий единственный метод.

Это "сработало бы", но более сложный вопрос - "следует" это сделать?Я думаю, что вы можете пересмотреть свою реализацию.

1 голос
/ 11 ноября 2010

Не совсем понятно, что вы надеетесь сделать, точно.Что вы ожидаете, если будет вызван первый метод?В зависимости от того, что вы ожидаете, вы можете заставить родительский абстрактный класс реализовать первый метод, исходя из предположения, что второй был реализован:

protected internal T DataFromXmlElements(IEnumerable<XmlNode> nodes) {
    return DataFromXmlElements(nodes, null);
}
1 голос
/ 11 ноября 2010

Абстрактный элемент ДОЛЖЕН быть реализован, так что я думаю, что пути назад нет.

Другим решением было бы определить вместо этого два интерфейса, каждый из которых содержит один из реализуемых элементов.Тогда реализующие классы могут реализовать один или оба интерфейса.

Например:

public interface BaseBarA<T> where T : BaseThing{
  protected internal abstract T DataFromXmlElements(IEnumerable<XmlNode> nodes);  
}

public interface BaseBarB<T> where T : BaseThing{
  T DataFromXmlElements(IEnumerable<XmlNode> nodes, string[] fieldNames);  
}
1 голос
/ 11 ноября 2010

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

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

1 голос
/ 11 ноября 2010

Я предполагаю, что вам понадобятся 2 или 3 абстрактных класса для достижения этого

public interface BaseBar1<T> // does one
public interface BaseBar2<T> // does the other
public interface BaseBar3<T> // does both

вы можете использовать необязательный параметр

internal abstract class BaseBar<T> where T : BaseThing
{
    protected internal abstract T DataFromXmlElements(
        IEnumerable<XmlNode> nodes, string[] fieldNames);
}

class FooBarMapper : BaseBar<FooData>
{
    protected internal override FooData DataFromXmlElements(
        IEnumerable<XmlNode> nodes, 
        [Optional] string[] fieldNames)
    {
        if (fieldNames == null) // skip stuff
        else // do stuff
    }

Подробнее о Необязательный атрибут .

0 голосов
/ 11 ноября 2010

Вы не можете сделать это.Единственный вариант - переставить классы.

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