views:

108

answers:

3

In my console application have an abstract Factory class "Listener" which contains code for listening and accepting connections, and spawning client classes. This class is inherited by two more classes (WorldListener, and MasterListener) that contain more protocol specific overrides and functions.

I also have a helper class (ConsoleWrapper) which encapsulates and extends System.Console, containing methods for writing to console info on what is happening to instances of the WorldListener and MasterListener.

I need a way to determine in the abstract ListenerClass which Inheriting class is calling its methods.

Any help with this problem would be greatly appreciated! I am stumped :X

Simplified example of what I am trying to do.

abstract class Listener
{
   public void DoSomething()
   {
      if(inheriting class == WorldListener)
      ConsoleWrapper.WorldWrite("Did something!");
      if(inheriting class == MasterListener)
      ConsoleWrapper.MasterWrite("Did something!");
   }
}

public static ConsoleWrapper
{
   public void WorldWrite(string input)
   {
       System.Console.WriteLine("[World] {0}", input);
   }
}

public class WorldListener : Listener
{
   public void DoSomethingSpecific()
   {
       ConsoleWrapper.WorldWrite("I did something specific!");
   }
}

public void Main()
{
   new WorldListener();
   new MasterListener();
}

Expected output

[World] Did something!
[World] I did something specific!
[Master] Did something!
[World] I did something specific!

+4  A: 

If you know each of the types you want to compare against, then use the is operator:

if (this is WorldListener)
{
 // ...
}
else if (this is MasterListener)
{
 // ...
}

Alternatively, you could use GetType if you want a little more flexibility:

var type = GetType();
// Do some logic on the type to determine what to do next.

You should be careful with this approach, however; it's generally indicative of bad design that you need to explicitly check for types (as these lovely people insist). Instead, it's almost always more appropriate to use polymorphism to delegate the desired behaviour to the base class (using a virtual or abstract method in the base class) – this is, after all, what it's designed for!

You might apply polymorphism something like this:

static class Program
{
    static void Main(string[] args)
    {
        Listener listener = new WorldListener();
        listener.DoSomething();
    }
}

abstract class Listener
{
    public void DoSomething()
    {
        var output = Decorate("Did something!");
        ConsoleWrapper.WriteLine(output);
    }

    protected abstract string Decorate(string input);
}

class WorldListener : Listener
{
    protected override string Decorate(string input)
    {
        return string.Format("[World] {0}", input);
    }
}

class MasterListener : Listener
{
    protected override string Decorate(string input)
    {
        return string.Format("[Master] {0}", input);
    }
}

This will produce the output [World] Did something!. The advantage of this approach is that if you ever want to add another type of listener, it's simply a matter of defining a new class for it with the appropriate Decorate method; there's no need to modify Listener itself.

Will Vousden
Great answer, wish I could choose more then one!
Kin
Wouldn't this cause me to have to delegate more to the inheriting classes? Almost all of the functions are re-used.
Kin
It's up to you how much you delegate; you could retain the bulk of the logic in `Listener` and just delegate the code for decorating the input (i.e. appending the `[World]` and `[Master]` tags).
Will Vousden
It sounds like I must be flawed in my understanding of abstract methods, thanks for your help.
Kin
@Kin: I've amended the example I gave to demonstrate.
Will Vousden
Even clearer, thanks. Would there be any issues in placing the Console.WriteLine in the override, rather then in the base class?
Kin
Well I don't think there'd be any advantages in doing so, and it would make it less versatile. Since the base class provides the common functionality for all concrete listener classes, it makes more sense to put the output logic in that rather than in the subclasses (unless it's possible that some listeners will output things differently, but then you might consider creating an abstract `Output` method instead). Remember the DRY principle: http://en.wikipedia.org/wiki/DRY.
Will Vousden
+2  A: 

Hmm.. Well, in your simplified example you don't call DoSomething() and DoSomethingSpecific(), and there's no implementation for MasterListener.. Also, if I understand it right, in your expected output your MasterListener.DoSomethingSpecific() runs a ConsoleWrapper.WorldWrite.. You probably meanr MasterWrite?

In any case.. Here's a working example that does what you want (at least in the way I understood your request :P )

The printed result is:

[World] Did something
[World] I did sth specific!
[Master] Did something
[Master] I did sth specific!

The code:

    void Main()
{
    var wl = new WorldListener();
    wl.DoSomething();
    wl.DoSpecific();
    var ml = new MasterListener();
    ml.DoSomething();
    ml.DoSpecific();
}

public abstract class Listener
{
    public abstract string Category { get; }
    public void DoSomething()
    {
        ConsoleWrapper.Write(Category, "Did something");
    }
}

public static class ConsoleWrapper
{
    public static void Write(string category, string input)
    {
        Console.WriteLine("[{0}] {1}", category, input);
    }
}

public class WorldListener : Listener
{
    public override string Category { get { return "World"; } }
    public void DoSpecific()
    {
        ConsoleWrapper.Write(Category, "I did sth specific!");
    }
}

public class MasterListener : Listener
{
    public override string Category { get { return "Master"; } }
    public void DoSpecific()
    {
        ConsoleWrapper.Write(Category, "I did sth specific!");
    }
}
Artiom Chilaru
Great answer thanks!
Kin
I've updated this example with what you might need - the Listener class doesn't depend on child inherited classes. Instead the child classes have to implement a Category property that will define which class has sent a string to the ConsoleWrapper.
Artiom Chilaru
+2  A: 

You can use

if (this is WorldListener)

instead of your pseudocode

if (inheriting class == WorldListener) 

However, doing this is a bad design smell. You should strongly consider an alternative solution, e.g. performing the write to the console wrapper in a virtual method instead of adding this strong coupling between the base class and its subclasses.

Jonas H
I will look into that, thanks!
Kin