2012-01-20 2 views
0

Я хочу создать абстрактный базовый класс для всех классов типа параметров для наследования в моем приложении. Все параметры будут иметь имя, идентификатор и требуемые свойства.Абстрактные классы и методы в C#

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

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

Я думал о чем-то наподобие переопределения событий на Control.

Вот пример того, о чем я думал, хотя он не работает.

abstract class ParameterBase 
{ 
    protected string ParameterName; 
    protected bool IsRequired; 
    protected int ParameterId; 

    public abstract void SetProperties(string xml) 
    { 
     this.ParameterName = XmlParser.GetParameterName(xml); 
     this.IsRequired = XmlParser.GetIsRequired(xml); 
     this.ParameterId = XmlParser.GetParameterId(xml); 
    } 
} 

abstract class Parameter1 : ParameterBase 
{ 
    private string _value; 

    public string ParameterName 
    { 
     get { return base.ParameterName; } 
    } 

    public bool IsRequired 
    { 
     get { return base.IsRequired; } 
    } 

    public int ParameterId 
    { 
     get { return base.ParameterId; } 
    } 

    public string Value 
    { 
     get { return _value; } 
    } 

    public Parameter1() 
    { 

    } 

    public override void SetProperties(string xml) 
    { 
     base.SetProperties(xml); 

     _value = XmlParser.GetValue(xml); 
    } 
} 
+1

Уточнитните «не работает.» Вы получаете исключение? Результаты, которых вы не ожидаете? –

+0

Извините - он даже не будет скомпилирован - вы не можете назвать абстрактного базового члена: base.SetProperties (xml); из дочернего класса – ChandlerPelhams

ответ

4

Я бы просто, как это:

abstract class ParameterBase 
{ 
    protected string ParameterName; 
    protected bool IsRequired; 
    protected int ParameterId; 

    public abstract void SetProperties(string xml); 

} 

и вывел один:

public class Parameter1 : ParameterBase 
{ 
    public override void SetProperties(string sml) 
    { 
     //set properties including those ones of parent 
    } 
} 

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

кодекс предусматривает имеет несколько проблем:

  • abstract метод не может иметь тело

  • у вас есть странное public override void SetValues(string xml) который я думаю, должно быть
    public override void SetProperties(string xml)

+0

Если все мои дочерние классы имеют одинаковые 3 свойства, почему бы не дать описанию базового класса значения для этих свойств? Поскольку значения задаются из XML, я не хочу, чтобы какой-либо из наборов дочерних классов был общедоступным, поэтому единственный способ изменить значения будет через метод SetProperties. – ChandlerPelhams

+1

Если вы хотите управлять таким образом, не объявляйте класс как 'abstract', а как простой базовый класс с' virtual' методом 'SetProperties'. В этом случае вы можете объявить тело внутри функции базового класса, поэтому доля его дочерних элементов не только свойств, но и функции. – Tigran

+0

@Tigran Исправьте меня, если я ошибаюсь в вашем абстрактном классе, не нарушая принцип SOILD, не так ли, но если вы реализуете с помощью виртуального тела, это нарушает твердый принцип. пожалуйста, очистите меня. – PEO

0

Вы делают это слишком сложным. Первые три свойства могут быть inhertied из базового класса:

public abstract class ParameterBase 
{ 
    public string ParameterName { get; private set; } 
    public bool IsRequired { get; private set; } 
    public int ParameterId { get; private set; } 

    public virtual void SetProperties(string xml) 
    { 
     ParameterName = XmlParser.GetParameterName(xml); 
     IsRequired = XmlParser.GetIsRequired(xml); 
     ParameterId = XmlParser.GetParameterId(xml); 
    } 
} 

public class Parameter1 : ParameterBase 
{ 
    public string Value { get; private set; } 

    public override void SetProperties(string xml) 
    { 
     base.SetProperties(xml); 
     Value = XmlParser.GetValue(xml); 
    } 
} 

Также отметим, что абстрактный метод не может иметь тело, вместо этого он завершается точкой с запятой:

public abstract void SetProperties(string xml); 

Вы должны delacre как виртуальный, если вы хотите дать ему базовую реализацию.

(И вы должны переопределить SetProperties, не SetValue.)

+0

Невозможно объявить тело внутри абстрактного метода, например, в 'SetProperties' – Tigran

+1

Да, я изменил его на виртуальный. –

0

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

protected string ParameterName { get; protected set; }; 
protected bool IsRequired { get; protected set; }; 
protected int ParameterId { get; protected set; }; 
1

Есть четыре проблемы с вашим кодом, что я могу видеть:

  1. Вы переосмысление 3 общих свойств, и вы пытаетесь назвать их так же, как существующее поле. Это запрещено.Самый простой способ - реализовать свойства в базовом классе так же, как вы внедрили Value в классе наследования: с полями поддержки. В C# 3.0 и выше (Visual Studio 2008 и выше) вы можете использовать автоматически реализованные свойства с помощью частного сеттера. Это заставит компилятор создать для вас поля поддержки. Например:

    public string ParameterName { get; private set; }
  2. Вы объявляете метод SetProperties как abstract. Это должно быть virtual. abstract означает, что подкласс должен определять всю реализацию. Здесь дело не в этом.

  3. В вашем производном классе вы переопределяете SetValues, но метод называется SetProperties.

  4. Вы объявляете Parameter1 абстрактным. Вы не можете создавать абстрактные классы, поэтому вам нужно было бы наследовать класс от Parameter1, а также для его использования. Я предполагаю, что вы просто захотите удалить квалификатор abstract.

+0

Argh - так много ошибок: p. Я определенно думал о виртуальном методе, а не о абстрактном. – ChandlerPelhams

0

Как отмечено, не надо думать. Я объявляю абстрактный класс параметров, чтобы иметь один конструктор (защищенный), который принимает обязательные три свойства (Name, IsRequired и ID). Это означает, что каждый конкретный подтип должен правильно его построить.

Тогда у меня будет аннотация фабричный метод, CreateInstance(), который должен реализовать каждый конкретный подтип, возвращая экземпляр AbstractParameter. Зачем? Читайте на Liskov Substitution Principle. Разумеется, в реальном мире может возникнуть больше смысла, чем использовать фабричный метод , отделить вопрос о том, как создавать экземпляры параметров из соображений , являющегося параметром, путем перемещения логики построения в ее собственный заводской класс (AbstractParameterFactory?).

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

Во всяком случае, вот мой AbstractParameter класс:

public abstract class AbstractParameter 
{ 
    public string Name  { get ; protected set ; } 
    public bool IsRequired { get ; protected set ; } 
    public int ID   { get ; protected set ; } 

    protected AbstractParameter(string name , bool isRequired , int id) 
    { 
     this.Name  = name; 
     this.IsRequired = isRequired; 
     this.ID   = id; 
     this.Value  = default(T) ; 
     return; 
    } 

    public abstract AbstractParameter CreateInstance(string xml) ; 

} 

Конкретный класс параметр, который является производным от AbstractParameter может выглядеть примерно так:

public class ConcreteParameter : AbstractParameter 
{ 
    public ConcreteParameter(string name , bool isRequired , int id) : base(name , isRequired , id) 
    { 
     return ; 
    } 

    public override AbstractParameter CreateInstance(string xml) 
    { 
     string   name  = XmlParser.GetName(); 
     bool    required = XmlParser.GetIsRequired(); 
     int    id  = XmlParser.GetID(); 
     ConcreteParameter instance = new ConcreteParameter(name , required , id); 

     return instance; 
    } 

} 
Смежные вопросы