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?
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'.");
}
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() { }
}
Related
Yeah, I know there aren't any virtual static members in c#, but I have a problem where they would be really helpful and I can't see a good way to proceed.
I've got a standard kind of system where I send packets of data over a communication channel and get back responses. The communication system needs to know how many bytes of response to wait for, and the length of the response is fixed for each command type, so I have this code defined:
public abstract class IPacket
{
public abstract int ReceiveLength { get; }
public abstract byte[] DataToSend();
}
public class Command1 : IPacket
{
public override int ReceiveLength { get { return 3; } }
public Command1() { }
}
public class Command2 : IPacket
{
public override int ReceiveLength { get { return DataObject.FixedLength; } }
public Command2(int x) { }
}
public class Command3 : IPacket
{
static DataHelperObject Helper;
public override int ReceiveLength { get { return Helper.DataLength(); } }
static Command3()
{
Helper = new DataHelperObject();
}
public Command3(really long list of parameters containing many objects that are a pain to set up) { }
}
Notice that in each case, ReceiveLength is a fixed value - sometimes it's a simple constant (3), sometimes it's a static member of some other class (DataObject.FixedLength) and sometimes it's the return value from a member function of a static member (Helper.DataLength()) but it's always a fixed value.
So that's all good, I can write code like this:
void Communicate(IPacket packet)
{
Send(packet.DataToSend());
WaitToReceive(packet.ReceiveLength);
}
and it works perfectly.
But now I would like to output a summary of the packets. I want a table that shows the command name (the class name) and the corresponding ReceiveLength. I want to be able to write this (pseudo)code:
foreach (Class cls in myApp)
{
if (cls.Implements(IPacket))
{
Debug.WriteLine("Class " + cls.Name + " receive length " + cls.ReceiveLength);
}
}
But of course ReceiveLength requires an object.
I don't think I can use attributes here, c# won't let me say:
[PacketParameters(ReceiveLength=Helper.DataLength())]
public class Command3 : IPacket
{
static DataHelperObject Helper;
static Command3()
{
Helper = new DataHelperObject();
}
public Command3(really long list of parameters containing many objects that are a pain to set up) { }
}
because custom attributes are created at compile time (right?), long before the static constructor gets called.
Constructing objects of each type isn't particularly pleasant (pseudocode again):
foreach (Class cls in myApp)
{
IPacket onePacket;
if (cls is Command1)
onePacket = new Command1();
else if (cls is Command2)
onePacket = new Command2(3);
else if (cls is Command3)
{
Generate a bunch of objects that are a pain to create
onePacket = new Command3(those objects);
}
Debug.WriteLine("Class " + cls.Name + " receive length " + onePacket.ReceiveLength);
}
I need ... a virtual static property.
One solution would be to throw all compile-time safety over board and simply use reflection to access your static property like so: http://fczaja.blogspot.ch/2008/07/accessing-static-properties-using-c.html
Alternatively, you could separate out that information into a "PaketSizeManager" type which would simply have either the above-mentioned Dictionary or some switch-case statement plus some neat way to access this information from the outside, as in a public int GetSize(Type t){ .../* use dictionary or switch-case here */... } method. That way you would have encapsulated the size aspect of all your entities into a separate class.
Just make a public static CommandX.Length property, have it return what your ReceiveLength property is now, then have ReceiveLength refer to it. To get the best of both worlds, first you need both worlds.
I have a nested class within an outer class and from within the inner class I would like to get the name of the outer class via reflection at runtime.
public abstract class OuterClass // will be extended by children
{
protected class InnerClass // will also be extended
{
public virtual void InnerMethod()
{
string nameOfOuterClassChildType = ?;
}
}
}
Is this possible in c#?
Edit: I should add, that I want to use reflection and get the name from a child class which extens from OuterClass, which is the reason, I don't know the concrete type at compile time.
Something like this should parse out the name of the outer class:
public virtual void InnerMethod()
{
Type type = this.GetType();
// type.FullName = "YourNameSpace.OuterClass+InnerClass"
string fullName = type.FullName;
int dotPos = fullName.LastIndexOf('.');
int plusPos = fullName.IndexOf('+', dotPos);
string outerName = fullName.Substring(dotPos + 1, plusPos - dotPos - 1);
// outerName == "OuterClass", which I think is what you want
}
Or, as #LasseVKarlsen proposed,
string outerName = GetType().DeclaringType.Name;
...which is actually a better answer.
Maybe the most mystifying thing to me in C# is that the Exception class's message property is read-only. Probably because I don't understand the reason for this, I am frustrated when I try to create reasonable exception classes derived from Exception.
For example (and actually what I'm trying to do), I want to create an exception to raise when an attempt to connect to an OPC server. An object of type OPCException is raised if the attempt fails, but I want to give the user more information. So, I have a class named OPCCaException that takes three arguments: the return code from the original exception, the server name, and the host name.
public class OPCCaException : Exception
{
public OPCCaException(ReturnCode returnCode, string serverName, string nodeName)
{
if (nodeName == "")
{
this.Message = "Failed to connect to OPC server "+ serverName +
": " + TranslateReturnCode()";
}
else
{
this.Message = "Failed to connect to OPC server "+ serverName +
" on node " + nodeName +
": " + TranslateReturnCode()";
}
}
}
This seems to me to be a perfectly reasonable thing to do, but it won't compile because the Message property is read-only. The only way to set the message is to pass it to the base class constructor. Why can't I set it in my derived class's constructor? The only way I can think of to do any kind of processing on the arguments is to create a static class to build the message:
public class OPCCaException : Exception
{
private static string BuildMessage(<some arguments>)
{
string message = "some message";
return message;
}
public OPCCaException(ReturnCode returnCode, string serverName, string nodeName) :
base(BuildMessage(returnCode, serverName, nodeName))
{
}
}
I don't know if that will compile.
What is the standard way to do this?
public virtual string Message
Message is virtual - so you can easily override it in your class.
public class OPCCaException : Exception
{...
public override string Message
{
get { return "My fancy text";}
}
}
Also more standard way of doing it is to pass message via call to base class constructor:
public OPCCaException(...) : base(buildMessage(...))
{
}
Why is the exception message property read only?
Because exceptions are meant to stay intact as they travel up the stack trace. If, as you capture, you want to provide more information/meaningful message you should wrap the captured exception in another exception. There is a constructor that does exactly that.
This seems to me to be a perfectly reasonable thing to do, but it won't compile because the Message property is read-only.
What you're trying to achieve is perfectly reasonable. The way you're trying to achieve is not. Since Message property is read-only nobody can assign anything to it, including you. For this reason it was made virtual. Read more about overriding it on MSDN.
You can either pass the message to the base class constructor, or you can override the Message property on your class to return something else. For example:
public class OPCCaException : Exception
{
ReturnCode returnCode;
string serverName;
string nodeName;
public OPCCaException(ReturnCode returnCode, string serverName, string nodeName)
: base();
{
this.returnCode = returnCode;
this.serverName = serverName;
this.nodeName = nodeName;
}
public override string Message
{
get
{
return string.Format("Failed to connect to OPC server {0}{1}: {2}",
serverName,
string.IsNullOrEmpty(nodeName ? "" : " on node " + nodeName),
TranslateReturnCode(returnCode)
);
}
}
}
Have you noticed that Exception.Message is a virtual property? The appropriate way to handle this would be to override Message and provide your own implementation
public class MyException : Exception
{
private string myMessage = null;
public override string Message
{
get
{
return String.IsNullOrEmpty(myMessage) ?
base.Message :
myMessage;
}
}
public MyException(string message) : base()
{
myMessage = message;
}
}
I'm going to do my best to explain my vision here. This is a very lame made-up example. I've got a few different types of Bags, and they all hold their own special type of Marble. Each type of Marble has its own set of Nicknames (strings).
Unfortunately, there are other things besides the Marble in the Bag, so generics won't help me here.
// Bags
abstract class Bag {
protected Type MarbleType { get; }
protected List<Marble> _marbles;
public void DumpBag()
{ ... }
}
class RedBag : Bag {
override Type MarbleType { get { return typeof(RedMarble); } }
}
class BlueBag : Bag {
override Type MarbleType { get { return typeof(BlueMarble); } }
}
// Marbles
abstract class Marble {
public static IEnumerable<string> Nicknames {
get {
return new List<string>() {
"Marble", "RollyThing"
}
}
}
}
class RedMarble : Marble {
public static IEnumerable<string> Nicknames {
get {
return new List<string>(Marble.Nicknames) {
"Ruby"
};
}
}
}
class BlueMarble : Marble { ... }
So now we get to the details, the implementation of DumpBag(). Consider the following call:
Bag b = new RedBag();
b.GetMarbles();
b.DumpBag();
I would like it to print:
Bag of Marbles (aka "Marble", "RollyThing", Ruby"):
- Marble 1
- Marble 2
...
We see that, in order to print that heading, the Bag must be able to have knowledge of the derived type of Marble, independent of any actual instances. It gets a concatenation of the Nicknames of the Marble base class, but also the derived RedMarble.
DumpBag needs to do a kind of 'static virtual call'. I've started implementing DumpBag with the following:
public void DumpBag() {
PropertyInfo pi = this.MarbleType.GetProperty("Nicknames", BindingFlags.Static);
IEnumerable<string> nicknames = pi.GetValue(null, null); // No instance
StringBuilder sb = new StringBuilder("Bag of Marbles (aka ");
foreach (string nn in nicknames)
sb.Append("\"" + nn + "\", ");
Console.WriteLine(sb.ToString());
...
}
My questions:
Is this sane? Hopefully I have (or I can) explain my rationale for why I've gone this route.
I get a warning (of course) that RedMarble.Nicknames hides Marble.Nicknames. Does it seem valid to go ahead and mark it new?
You'll find all you're missing is an explicit cast:
(List<string>)this.MarbleType.GetProperty("Nicknames").GetValue(null, null);
This worked fine for me when I tested it.
And as discussed in the comments, no you shouldn't be using the new keyword really, you're better off naming the base class static method to something else so there is no ambiguity. You are after all in control of this and not using someone else's code.
Now, should you do it this way?
Well, first surely you want to use generics not defined methods to return types:
abstract class Bag<T> where T:marble {
public void DumpBag()
{
// here you can use
// (IEnumerable<string>)typeof(T).GetProperty("Nicknames").GetValue(null, null);
}
}
class RedBag : Bag<RedMarble> {
}
class BlueBag : Bag<BlueMarble> {
}
Of course the second thing you could do is make this not static, in which case the property will be abstract in Marble, and overridden in RedMarble and BlueMarble, and then just accessed in DumpBag directly as Nicknames rather than using reflection.
Does this give any code smell or violate SOLID principles?
public string Summarize()
{
IList<IDisplayable> displayableItems = getAllDisplayableItems();
StringBuilder summary = new StringBuilder();
foreach(IDisplayable item in displayableItems)
{
if(item is Human)
summary.Append("The person is " + item.GetInfo());
else if(item is Animal)
summary.Append("The animal is " + item.GetInfo());
else if(item is Building)
summary.Append("The building is " + item.GetInfo());
else if(item is Machine)
summary.Append("The machine is " + item.GetInfo());
}
return summary.ToString();
}
As you can see, my Summarize() is tied to implementation classes such as Human, Animal, etc.
Is this code violating LSP? (Any other SOLID principles?)
I smell a little something...
If your classes all implement IDisplayable, they should each implement their own logic to display themselves. That way your loop would change to something much cleaner:
public interface IDisplayable
{
void Display();
string GetInfo();
}
public class Human : IDisplayable
{
public void Display() { return String.Format("The person is {0}",
GetInfo());
// Rest of Implementation
}
public class Animal : IDisplayable
{
public void Display() { return String.Format("The animal is {0}",
GetInfo());
// Rest of Implementation
}
public class Building : IDisplayable
{
public void Display() { return String.Format("The building is {0}",
GetInfo());
// Rest of Implementation
}
public class Machine : IDisplayable
{
public void Display() { return String.Format("The machine is {0}",
GetInfo());
// Rest of Implementation
}
Then you can change your loop to something much cleaner (and allow the classes to implement their own display logic):
foreach(IDisplayable item in displayableItems)
summary.Append(item.Display());
seems like IDisplayable should have a method for the display name so you can reduce that method to something like
summary.Append("The " + item.displayName() + " is " + item.getInfo());
Yes.
Why not have each class implement a method from IDisplayable that shows their type:
interface IDisplayable
{
void GetInfo();
public string Info;
}
class Human : IDisplayable
{
public string Info
{
get
{
return "";//your info here
}
set;
}
public void GetInfo()
{
Console.WriteLine("The person is " + Info)
}
}
Then just call your method as follows:
foreach(IDisplayable item in displayableItems)
{
Console.WriteLine(item.GetInfo());
}
Given the comment on this answer from the OP, I think the best approach would be to create a custom container class to replace IList<IDisplayable> displayableItems which has methods like containsHumans() and containsAnimals() so you can encapsulate the icky non-polymorphic code in one place and keep the logic in your Summarize() function clean.
class MyCollection : List<IDisplayable>
{
public bool containsHumans()
{
foreach (IDisplayable item in this)
{
if (item is Human)
return true;
}
return false;
}
// likewise for containsAnimals(), etc
}
public string Summarize()
{
MyCollection displayableItems = getAllDisplayableItems();
StringBuilder summary = new StringBuilder();
if (displayableItems.containsHumans() && !displayableItems.containsAnimals())
{
// do human-only logic here
}
else if (!displayableItems.containsHumans() && displayableItems.containsAnimals())
{
// do animal-only logic here
}
else
{
// do logic for both here
}
return summary.ToString();
}
Of course my example is overly simple and contrived. For instance, either as part of the logic in your Summarize() if/else statements, or perhaps surrounding the entire block, you'll want to iterate over the displayableItems collection. Also, you'll likely get better performance if you override Add() and Remove() in MyCollection and have them check the type of the object and set a flag, so your containsHumans() function (and others) can simply return the state of the flag and not have to iterate the collection every time they're called.
How about:
summary.Append("The " + item.getType() + " is " + item.GetInfo());
At a minimum it violates LSP and Open-Closed Principle.
The solution is to have a Description property to the IDisplayable interface, so that summarize can just call
summary.Append(string.Format("The {0} is {1}", item.Description, item.GetInfo()));
This could also be solved via reflection, since you're only getting the name of the class.
The better solution is to return something like an IDisplayableInfo from the GetInfo() method. This would be an extensibility point to help preserve OCP.
If you can't modify IDisplayable or the class implementations and you're using .NET 3.5 or later you can use Extension methods. But that's not that much better