views:

97

answers:

4

I have a abstact class named Organism which has a Born event. Also I have some classes that inherit the Organism class... So my question is how can I raise the Born event among all instances of all classes, which inherited the Organism class?

EDIT: Sorry, The event I meant to write was Tick not Born... Born is a instance level event...

A: 

There is no way to get a list of all instances of some class, so you have to keep track of new instances yourself:

List<Organism> organisms = new List<Organism>();

Organism bob = new Amoeba();
organisms.Add(bob);

Later you can iterate your list of instances and make them all raise the event, one after another:

foreach (Organism organism in organisms)
{
    organism.Awake();
}
dtb
And the logical place for organisms.Add() would be the Organism constructor.
Henk Holterman
@Henk: I was thinking about it, but object destruction would be complicated. Possibly implement IDisposable, which would remove them from the static list so they can be disposed.
Yuriy Faktorovich
@Henk: Maybe. Maybe not. Actually, I was struggling to find a good name for the method that breathes life into an organism and raises the `Born` event. You "get born" or "give birth", you you don't become magically alive. Maybe a parent organism should have a method to give birth to a new child organism? :)
dtb
Almost regardless of your religious affiliation, one day something had to have come alive without parents.
Yuriy Faktorovich
A parent organism sounds like an instance of the Factory Pattern, where the created objects are factories themselves. But who instantiates the first factory? I fear there is no way around creationism in C# ;-)
dtb
There is no such thing as the first factory, it is a static class, it was always there.
Yuriy Faktorovich
+2  A: 
Jimmy Hoffa
Is a static event really a good idea?
dtb
Maybe not necesarrily for an event, but a static list or some static that every Organism registers itself to at construction would seem the right way to go..
Jimmy Hoffa
Please note that the event will 'protect' organisms form the GC, just like a List would. A Dispose() is in order, along with the guidance to use it.
Henk Holterman
@henk-holterman: Fixed.
Jimmy Hoffa
Jimmy, the finalizer (destructor) has no function here but it is expensive.
Henk Holterman
A: 

It isn't great, but this might work:

public abstract class Organism : IDisposable
{
    private static readonly List<Organism> LiveOrganisms = 
        new List<Organism>();

    private event EventHandler onBorn;

    public void InvokeBorn(EventArgs e)
    {

        foreach (var liveOrganism in LiveOrganisms
            .Where(liveOrganism => liveOrganism.onBorn != null))
        {
            liveOrganism.onBorn(this, e);
        }
    }

    public event EventHandler Born
{
    add
    {
        onBorn += value;
    }
    remove
    {
        onBorn -= value;
    }
}

    protected Organism()
    {
        LiveOrganisms.Add(this);
    }

    public void Dispose()
    {
        LiveOrganisms.Remove(this);
    }
}
Yuriy Faktorovich
IMO an instance-level event and InvokeBorn doesn't make a lot of sense. It feels... weird... to have an instance-level method that affects more instances than itself. Wouldn't a static event and method be better?
dtb
@dtb: You're right, it does seem weird. But I though it really described the functionality asked in the question. I can't really think of a good use case for it in general.
Yuriy Faktorovich
Sorry, The event I meant to write was Tick not Born... Born is a instance level event...
Dimitar Vouldjeff
A: 

Why wouldn't each concrete organism invoke it's parent's Born event when it's birthed. Something like:

public abstract class Organism
{
    public event EventHandler<EventArgs> Born;
    public string Name { get; set; }

    public Organism()
    {
    }

    public void Birth()
    {
        this.raiseBorn(new EventArgs());
    }

    protected void raiseBorn(EventArgs args)
    {
        EventHandler<EventArgs> handler = this.Born;
        if (handler != null)
            handler(this, args);
    }
}

// Concrete organisms ========--------

public class Dog : Organism
{
    public Dog()
    {
        this.Name = "Dog";
    }

    public override string ToString()
    {
        return this.Name;
    }
}

public class Cat : Organism
{
    public Cat() 
    {
        this.Name = "Cat";
    }

    public override string ToString()
    {
        return this.Name;
    }
}

// Creature Factory ========--------

public class CreatureCreator : List<Organism>
{
    public event EventHandler<BornArgs> CreaturBorn;
    private void raiseCreatureBorn(BornArgs args)
    {
        EventHandler<BornArgs> handler = this.CreaturBorn;
        if (handler != null)
            handler(this.CreaturBorn, args);
    }

    public void CreateCreature<T>() where T : Organism, new()
    {
        Organism o = new T();
        o.Born += o_Born;
        this.Add(o);

        o.Birth();
    }

    private void o_Born(object sender, EventArgs e)
    {
        this.raiseCreatureBorn(new BornArgs((Organism)sender));
    }
}

public class BornArgs : EventArgs
{
    public Organism Creature { get; set; }

    public BornArgs(Organism o)
    {
        this.Creature = o;
    }
}

// Usage ========--------

static void Main(string[] args)
{
    CreatureCreator deity = new CreatureCreator();
    deity.CreaturBorn += deity_CreaturBorn;

    deity.CreateCreature<Dog>();
    deity.CreateCreature<Cat>();

    Console.ReadKey();
}

static void deity_CreaturBorn(object sender, BornArgs e)
{
    Console.WriteLine(e.Creature.ToString() + " was born");
}

output:

Dog was born
Cat was born
SnOrfus
The problem is that I wrote Born instead of Tick...
Dimitar Vouldjeff