In order to test inheritance and subclass overrides (the specific characteristics of a derived class, not necessarily with the 'override' keyword), I made these classes, meant to partially conjugate German language verbs.
The conjugation rules, oversimplified for my test, are as follows:
- the infinitive of the verb must end either in -en or -rn. Otherwise, an exception for invalid data must be thrown, both for the base class and the subclass.
- regular verbs (base class) have their 3rd person singular (he-person) ending in -t. In case this regular verb form does not end in -t, an exception must be thrown for the base class.
- a set of irregular verbs (called "modal" verbs) has its 3rd pers. sing. NOT in -t. In case the -t ending is detected, an exception must be thrown for the subclass.
The problem is: two of the aforementioned exceptions contradict each other. The irregular-verb class is meant to inherit most of the content from the regular-verb class, but it inherits the "no -t ending" exception, which it is supposed to override, so that its specific exception is thrown for the opposite reason.
My code is as follows:
The main class (GermanVerb), whose properties are the infinitive and the first three grammatical persons (I, you, he):
namespace HeyCs.MyClasses;
internal class GermanVerb
{
internal GermanVerb(string infin, string thirdPer)
{
if (infin.EndsWith("en") || infin.EndsWith("rn"))
Infin = infin;
else
throw new InvalidDataException("The infinitive doesn't obey the expected grammatical rules.");
/*
if (!thirdPer.EndsWith("t"))
throw new InvalidDataException("The 3rd person singular doesn't obey the expected grammatical rules.");
*/
if (!thirdPer.EndsWith("t"))
thirdPer = "t";
ThirdPer = thirdPer;
FirstPer = Infin.Substring(0, Infin.Length - 1);
if (ThirdPer.EndsWith("st"))
SecPer = ThirdPer;
else if (ThirdPer.EndsWith("t") && !ThirdPer.EndsWith("st"))
SecPer = ThirdPer.Substring(0, ThirdPer.Length - 1) "st";
}
private string? Infin { get; }
internal string? FirstPer { get; set; }
internal string? SecPer { get; set; }
internal string? ThirdPer { get; set; }
public void VerbConjSum()
Console.WriteLine(Infin ": " FirstPer ", " SecPer ", " ThirdPer);
}
Note that I commented out the exception I wanted to throw, because it's inadvertently inherited by the subclass GermanVerbLikeModal, even if I try to define a new condition for the InvalidDataException to occur. Instead, I set a temporary workaround, in which the -t ending is automatically added to the he-form of the regular verb, in case it's absent.
Here's the code for the subclass:
namespace HeyCs.MyClasses;
internal class GermanVerbLikeModal : GermanVerb
{
internal GermanVerbLikeModal(string infin, string thirdPer) : base(infin, thirdPer)
{
if (thirdPer.EndsWith("t"))
throw new InvalidDataException("The 3rd. person singular doesn't obey the expected grammatical rules.");
ThirdPer = thirdPer;
FirstPer = ThirdPer;
if (ThirdPer.EndsWith("ss"))
SecPer = ThirdPer "t";
else
SecPer = ThirdPer "st";
}
}
And here's the Program.cs file, where I create an instance of a regular verb, and an instance of an irregular verb:
using HeyCs.MyClasses;
var trinkenVerb = new GermanVerb("trinken", "trinkt"); // Verb 'trinken', meaning 'to drink'
var sollenVerb = new GermanVerbLikeModal("sollen", "soll"); // Verb 'sollen', meaning 'should'
trinkenVerb.VerbConjSum();
sollenVerb.VerbConjSum();
The result in the console is:
trinken: trinke, trinkst, trinkt
sollen: soll, sollst, soll
I mentioned it just to give context to my problem. This is the expected output with valid data: for both verbs, infinitive in -en. For the 3rd person, -t ending for base verbs, non-t-ending for derived verbs.
So, I want to create three custom exceptions. One of them is common to both classes. Meanwhile, these classes have a unique exception each. But the subclass keeps inheriting the contradicting exception that it is meant not to inherit: activating the 'absent -t' exception for the base class, the verb "sollen" throws an exception because of the 'soll' form.
Even though I found a workaround, which omits the 'absent -t' exception altogether, is there a way to cancel that exception specifically for the subclass?
CodePudding user response:
You can use method overriding
add this method to the Base class and call it from the constructor:
protected virtual void CheckThirdPer(string thirdPer)
{
if (!thirdPer.EndsWith("t"))
throw new InvalidDataException("The 3rd person singular doesn't obey the expected grammatical rules.");
}
Override the method in child class
protected override void CheckThirdPer(string thirdPer)
{
if (thirdPer.EndsWith("t"))
throw new InvalidDataException("The 3rd. person singular of a modal verb doesn't end in '-t'.");
}
CodePudding user response:
The easiest way to handle this would be to offload checks into separate functions, each responsible for one check. This way, you can override
specific behavior for each check.
As an example, your main class may look like this:
namespace HeyCs.MyClasses;
internal class GermanVerb
{
internal GermanVerb(string infin, string thirdPer)
{
if (!infin.EndsWith("en") && !infin.EndsWith("rn"))
throw new InvalidDataException("The infinitive doesn't obey the expected grammatical rules.");
Infin = infin;
if (!thirdPer.EndsWith("t"))
HandleThirdPer();
if (!thirdPer.EndsWith("t"))
thirdPer = "t";
ThirdPer = thirdPer;
FirstPer = Infin.Substring(0, Infin.Length - 1);
if (ThirdPer.EndsWith("st"))
SecPer = ThirdPer;
else if (ThirdPer.EndsWith("t") && !ThirdPer.EndsWith("st"))
SecPer = ThirdPer.Substring(0, ThirdPer.Length - 1) "st";
}
private string? Infin { get; }
internal string? FirstPer { get; set; }
internal string? SecPer { get; set; }
internal string? ThirdPer { get; set; }
public void VerbConjSum() => Console.WriteLine(Infin ": " FirstPer ", " SecPer ", " ThirdPer);
protected virtual void HandleThirdPer() => throw new InvalidDataException("The 3rd person singular doesn't obey the expected grammatical rules.");
}
And your subclass like this:
internal class GermanVerbLikeModal : GermanVerb
{
internal GermanVerbLikeModal(string infin, string thirdPer) : base(infin, thirdPer)
{
ThirdPer = thirdPer;
FirstPer = ThirdPer;
SecPer = ThirdPer.EndsWith("ss") ? ThirdPer "t" : ThirdPer "st";
}
protected override void HandleThirdPer() { }
}