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);
}
}
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)
There are four issues with your code that I can see:
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; }
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.
In your derived class, you override SetValues but the method is called SetProperties.
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.
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; };
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.)
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;
}
}
Related
Using C# 10 and Net 6 I have (simplified code):
public class DefaultsBase {
public Int32 Repeats { get; set; } = 10;
}
public abstract class StrategyBase {
public abstract String Name { get; }
public abstract DefaultsBase Defaults { get; }
}
public class MonthlyStrategy : StrategyBase {
public override String Name => "Monthly Strategy";
public override MonthlyStrategyDefaults Defaults = new MonthlyStrategyDefaults();
public String Street { get; }
private class MonthlyStrategyDefaults : DefaultsBase {
public Int32 Window { get; } = 20;
};
public MonthlyStrategy(String street, Action<MonthlyStrategyDefaults> defaultsConfiguration) {
defaultsConfiguration(Defaults);
Street = street;
}
}
What I am trying to accomplish is:
1 - Create Strategy classes that derive from StrategyBase;
2 - In each Strategy being able to create a StrategyDefaults derived from DefaulstBase.
3 - Use an Action in constructor to change a few or all Strategy's Defaults including the ones on DefaultsBase.
I am not sure if my implementation makes sense and I am also getting the errors:
public override MonthlyStrategyDefaults Defaults
> The modifier 'override' is not valid for this item
public MonthlyStrategy(String street, Action<MonthlyStrategyDefaults> defaultsConfiguration)
> Inconsistent accessibility:
parameter type 'Action<MonthlyStrategy.MonthlyStrategyDefaults>' is
less accessible than method 'MonthlyStrategy.MonthlyStrategy(string, Action<MonthlyStrategy.MonthlyStrategyDefaults>)
How to do this?
first error
to override a property in the base class, it should has the same type and name
public override MonthlyStrategyDefaults Defaults = new MonthlyStrategyDefaults();
change it to
public override DefaultsBase Defaults = new MonthlyStrategyDefaults();
second error
In the public method MonthlyStrategy you try to give it a private class as a parameter Action<MonthlyStrategyDefaults> ... how the caller object would instantiate or deals with a private class! ...
you have three solutions
Change the accessibility for MonthlyStrategyDefaults and make it public
Or you can configur based on base class, Action<DefaultsBase> instead of Action<MonthlyStrategyDefaults>
Or make all configuration internally
I'm having a hard time phrasing the question which is also making it hard for me to search for answers.
Here's a contrived scenario that mimics what I'd like to do:
void Main()
{
Console.WriteLine(TestClassA.MyPropertyName());
Console.WriteLine(TestClassB.MyPropertyName());
var speaker = new TestSpeaker();
speaker.Speak<TestClassA>();
speaker.Speak<TestClassB>();
}
public class TestSpeaker {
public void Speak<T>() where T : BaseClass<T> {
Console.WriteLine(/* I want to call T.MyPropertyName() here */);
}
}
public class TestClassA : BaseClass<TestClassA> {
public string Name { get; set; }
}
public class TestClassB : BaseClass<TestClassB> {
public string OtherPropertyName { get; set; }
}
public abstract class BaseClass<T> {
public static string MyPropertyName(){
return typeof(T).GetProperties().Single().Name;
}
}
The Console right now would read:
Name
OtherPropertyName
I'd like to replace my commented out code so that it would read:
Name
OtherPropertyName
Name
OtherPropertyName
if you change your Writeline to
Console.WriteLine(BaseClass<T>.MyPropertyName());
you will get what you want
Why use a static function in a base class to retrieve information about a derived class? In any case, you could implement a member function to wrap the static call:
public static string MyStaticFunction() => return "whatever";
public string MyMemberFunction() => MyStaticFunction();
But in your scenario, perhaps you should simply declare an abstract property (or function) meant to return the value you're looking for and override it in derived classes:
Base:
public abstract string MyPropertyName { get; }
Derived:
public override string MyPropertyName => nameof(OtherPropertyName); // or more complex logic
And yet another possible solution would be to pass the information to the base class's constructor as a string (or property expression should you be so inclined):
Base:
public string MyPropertyName { get; init; }
public BaseClass(string propertyName)
{
MyPropertyName = propertyName; // maybe validate that the property exists
}
Derived:
public MyTestClassB() : BaseClass(nameof(OtherPropertyName)) {}
Code tells more than words, so look at this:
public abstract class ViewObject: INotifyPropertyChanged {
public virtual string Id {
get {
return this.GetType().Name;
}
}
}
public class Object : ViewObject {
private string id = string.Empty;
public override string Id {
get {
return this.id;
}
set {
this.id = value;
}
}
}
What is the correct way to implement the desired behaviour of a base implementation in the abstract class (yes, it should have a base implementation for this, but not for other things)?
I can only think of using the new keywork instead of override to simply hide the base implementation, but is this right?
you are already using inheritance. Override method is useful when method name and parameter is same.
here you can use method overloading.
for method overload name is same but parameter is different. you can use in inheritance also.
i hope this is useful
If you use the new keyword and someone casts your derived object to the base class, the base implementation will be called and not the derived one. To avoid this, the override is needed.
But that is currently not possible, cause your base class doesn't support a setter. So stick to the override and implement a set method in the base class that simply throws a NotSupportedExecption.
public abstract class ViewObject
{
public virtual string Id
{
get { return this.GetType().Name; }
set { throw new NotSupportedException(); }
}
}
public class Object : ViewObject
{
private string id = string.Empty;
public override string Id
{
get { return this.id; }
set { this.id = value; }
}
}
using System;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(new B("MyName").Name);
}
}
abstract class A
{
public A(string name)
{
this.GetType().GetField("Name").SetValue(this, name);
}
}
class B : A
{
public B(string name)
: base(name)
{
}
public string Name
{
set;
get;
}
}
}
Is it possible to do something like that?
I can't stress how very, very, very bad this is. You are creating an inverse coupling that is convoluted, confusing and contrived, severely lacking in clarity, failing best practices and object oriented principals, which is going to create a maintenance and management nightmare for people implementing derivatives of your abstract class. Do the right thing!!
abstract class A
{
protected A(string name)
{
Name = name;
}
public abstract string Name
{
get;
protected set;
}
}
class B: A
{
public B(string name) : base(name)
{
}
private string m_name;
public override string Name
{
get { return "B Name: " + m_name; }
protected set
{
m_name = value;
}
}
}
It is possible, but i wouldn´t recommend to do that. The problem is that your base class knows to much about the class that are derived from it.
When you derive a class from your abstract base class that does not define the property Name you get an Exception on runtime.
If you expect that each class, that is derived from your base class, has a property Name, then it would be easier to define the Property Name in your abstract base class and set the property with you constructor.
It's really bad form to do that. Generally you should just call a method like 'SetPossibleData()', and force all children to implement it in a fashion they decide.
Why do you need to do this?
Use GetProperty() Method,
public A(string name)
{
this.GetType().GetProperty("Name").SetValue(this,name,null);
}
It would be really straight forward if every class initializes the fields and properties it defines. Why does B expect the base class initialize its Name?
abstract class A
{
public A()
{
}
}
class B : A
{
// I know, its trivial, but it does the same ...
public B(string name) : base()
{
Name = name;
}
public string Name { set; get; }
}
The only thing I could think of why you wrote this code is that the base class has some logic to initialize the field. Straight forward would be to let the derived class call the logic, but initialize the field itself:
abstract class A
{
public A()
{
}
protected string GenerateName(string someArg)
{
// complicated logic to generate the name
}
}
class B : A
{
public B(string someArg) : base()
{
Name = base.GenerateName(someArg);
}
public string Name { set; get; }
}
In C# can a constant be overridden in a derived class? I have a group of classes that are all the same bar some constant values, so I'd like to create a base class that defines all the methods and then just set the relevant constants in the derived classes. Is this possible?
I'd rather not just pass in these values to each object's constructor as I would like the added type-safety of multiple classes (since it never makes sense for two objects with different constants to interact).
It's not a constant if you want to override it ;). Try a virtual read-only property (or protected setter).
Read-only property:
public class MyClass {
public virtual string MyConst { get { return "SOMETHING"; } }
}
...
public class MyDerived : MyClass {
public override string MyConst { get { return "SOMETHINGELSE"; } }
}
Protected setter:
public class MyClass {
public string MyConst { get; protected set; }
public MyClass() {
MyConst = "SOMETHING";
}
}
public class MyDerived : MyClass {
public MyDerived() {
MyConst = "SOMETHING ELSE";
}
}
Unfortunately constants cannot be overridden as they are not virtual members. Constant identifiers in your code are replaced with their literal values by the compiler at compile time.
I would suggest you try to use an abstract or virtual property for what you would like to do. Those are virtual and as such can (must, in the case of an abstract property) be overridden in the derived type.
Constants marked with const cannot be overridden as they are substituted by the compiler at compile time.
But regular static fields assigned to constant values can. I've had such a case just now:
class Columns
{
public static int MaxFactCell = 7;
}
class Columns2 : Columns
{
static Columns2()
{
MaxFactCell = 13;
}
}
If I just redefined the MaxFactCell field in the derived class instead, polymorphism wouldn't work: code using Columns2 as Columns would not see the overriding value.
If you need to restrict write (but not read) access to the field, using readonly would prohibit redefining it in Columns2. Make it a property instead, that's slightly more code:
class Columns
{
static Columns()
{
MaxFactCell = 7;
}
public static int MaxFactCell { get; protected set; }
}
class Columns2 : Columns
{
static Columns2()
{
MaxFactCell = 13;
}
}
Edit: This can have unexpected behaviour, see Shai Petel's remark below.
You can hide the inherited constant in a derived class by declaring the new constant new. I'm not sure this is a good practice, though.
class A
{
protected const int MyConst = 1;
}
class B : A
{
new private const int MyConst = 2;
}
to Work off dten + Tracker1's answer but updated for c# 6
public class MyClass {
public virtual string MyConst =>"SOMETHING";
}
...
public class MyDerived : MyClass {
public override string MyConst =>"SOMETHING ELSE";
}
You can force derived classes to have a value for a constant (well, a read-only property)
Make an interface containing a read-only property.
Put that interface on the base class.
Example:
public interface IHasConstant
{
string MyConst { get; }
}