ChandlerPelhams
ChandlerPelhams

Reputation: 1678

Abstract classes and methods in C#

I want to create an abstract base class for all paramter-type classes to inherit from in my application. All paramters will have name, ID and required properties.

All parameters will have their properties set from XML via the SetProperties method (the XmlParser class shown below is just for demonstration).

Since all parameters will have the same 3 properties, I wanted the base class to set those properties but have the inheriting class extend the SetProperties method to set the additional properties it contains.

I was thinking of something like overriding events on a Control.

Here is a sample of what I was thinking, although it does not work.

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);
    }
}

Upvotes: 0

Views: 4806

Answers (5)

Nicholas Carey
Nicholas Carey

Reputation: 74267

As noted, don't over think it. I'd declare the abstract parameter class so that it has a single constructor (protected) that takes the mandatory three properties ( Name, IsRequired, and ID). This means that every concrete subtype must construct it properly.

Then, I'd have an abstract factory method, CreateInstance(), that every concrete subtype must implement, returning an instance of AbstractParameter. Why? Read up on the Liskov Substitution Principle. In the Real World, of course, it might make more sense to, rather than use a factory method, separate the concern of how to creating parameter instances from the concerns of being a parameter, by moving the construction logic into its own factory class (AbstractParameterFactory?).

I might note, though, that you're missing an essential property that all parameters will have: a Value. You might consider making your abstract parameter's base class generic.

Anyway, here's my AbstractParameter class:

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 ) ;

}

A concrete parameter class that derives from AbstractParameter might then look something like this:

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;
    }

}

Upvotes: 0

Jeffrey Sax
Jeffrey Sax

Reputation: 10313

There are four issues with your code that I can see:

  1. You are redefining the 3 shared properties, and you're trying to name them the same as an existing field. This is not allowed. The simplest way is to implement the properties in the base class in the same way you implemented Value in the inheriting class: with backing fields. In C# 3.0 and above (Visual Studio 2008 and up), you can use auto-implemented properties with a private setter. This will make the compiler create the backing fields for you. For example:

    public string ParameterName { get; private set; }
  2. You are declaring the SetProperties method as abstract. This should be virtual. abstract means that the subclass must define the entire implementation. That's not the case here.

  3. In your derived class, you override SetValues but the method is called SetProperties.

  4. You are declaring Parameter1 as abstract. You can't instantiate abstract classes, so you would have to inherit a class from Parameter1 as well in order to use it. I'm guessing you would just want to remove the abstract qualifier.

Upvotes: 1

Olivier Jacot-Descombes
Olivier Jacot-Descombes

Reputation: 112352

You are making it too complicated. The first three properties can be inhertied from the base class:

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);
    }
} 

Also note that an abstract method cannot have a body, instead it is terminated by a semicolon:

public abstract void SetProperties(string xml);

You must delacre it as virtual if you want to give it a base implementation.

(And you must override SetProperties, not SetValue.)

Upvotes: 0

Tigran
Tigran

Reputation: 62246

I would do simply, like this:

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

    public abstract void SetProperties(string xml);

}

and derived one:

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

It's easy and clearer to manage in this way. Move common properties in separate base class it's good, but persistance management (Save/Load), leave to children. They should know how to do that.

Code provided has a couple of problems:

  • abstract method can not have body

  • you have strange public override void SetValues(string xml) which I think should be
    public override void SetProperties(string xml)

Upvotes: 4

Lloyd
Lloyd

Reputation: 2942

I would make the common Base class properties Public with protected setters, then you can access them from any derived classes, no use duplicating code!

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

Upvotes: 0

Related Questions