Eldar
Eldar

Reputation: 153

Cast different objects and call a method in same line?

I have the code:

        foreach(var o in objects)
        {
            o.Update(time);

            if(o is Portal)
            {
                var a = (Portal)o;
                a.Interact(ref player, player.Interact);
            }
            else if(o is Enemy)
            {
                var e = (Enemy)o;
                e.Update(time, player);
            }
        }

I don't know if anything like this is possible?

I want to do it in one line. This is what I have in mind:

(Enemy)o => Update(time, player);

I know it's stupid but I want something similar. The method that has player as a parameter is unique to the Enemy object. I have to parse to call it.

Upvotes: 6

Views: 1460

Answers (6)

Roman
Roman

Reputation: 12171

You can make your loop simpler (in case you use C# 6 or higher):

foreach(var o in objects)
{
    o.Update(time);

    (o as Portal)?.Interact(ref player, player.Interact);
    (o as Enemy)?.Update(time, player);           
}

For C# 5 or lower you should use:

foreach(var o in objects)
{
    o.Update(time);

    if (o is Portal)
    {
        ((Portal)o).Interact(ref player, player.Interact);
    }
    else if(o is Enemy)
    {
        ((Enemy)o).Update(time, player);
    }
}

In this case you have less lines of code but you cast two times.

You can cast only one time:

foreach(var o in objects)
{
    o.Update(time);

    var e = o is Portal;
    if (e != null)
    {
        e.Interact(ref player, player.Interact);
    }
    else
    {
        ((Enemy)o).Update(time, player);
    }
}

Upvotes: 8

Orace
Orace

Reputation: 8359

To go further than other response, you could use the visitor pattern.

First create a IVisitorClient and a IVisitor interface.

interface IVisitorClient
{
    Accept(IVisitor visitor);
}

interface IVisitor
{
    Visit(SceneObject o); // here the types of your objects
    Visit(Enemy e);
    Visit(Portal p);
}

Make your different object implement IVisitorClient.

abstract class SceneObject : IVisitorClient
{
    public virtual void Accept(IVisitor visitor)
    {
         visitor.Visit(this);
    }
}

class Portal : SceneObject
{
...

    public override void Accept(IVisitor visitor)
    {
         visitor.Visit(this);
    }
...
}

class Enemy: SceneObject
{
...

    public override void Accept(IVisitor visitor)
    {
         visitor.Visit(this);
    }
...
}

Then build an updater that implement IVisitor :

class UpdaterVisitor : IVisitor
{
    readonly Player player;
    readonly Time time;

    public UpdaterVisitor(Player player, Time time)
    {
        this.player = player;
        this.time = time;
    }

    public void Visit(SceneObject o)
    {
        e.Update(time);
    }

    public void Visit(Enemy e)
    {
        e.Update(time, player);
    }

    public void Visit(Portal p)
    {
        p.Interact(ref player, player.Interact);
    }
}

Finally, to update the object, the code will look like this.

var updateVisitor = new UpdaterVisitor(player, time);
foreach(var o in objects)
{
    o.Accept(updateVisitor);
}

Upvotes: 1

Justin Harvey
Justin Harvey

Reputation: 14672

Or do it this way to avoid the double cast...

foreach(var o in objects)
{
    o.Update(time);

    Portal p = o as Portal;

    if(p != null)
    {
        p.Interact(ref player, player.Interact);
    }
    else
    {
        Enemy e = o as Enemy;
        if (e != null)
        {
            e.Update(time, player);
        }
    }
}

Upvotes: 0

Pawel Maga
Pawel Maga

Reputation: 5787

Try this:

((Enemy)o).Update(time, player);

Remember about possible Null Reference Exception if you didn't check a type of this object. In your code everything is fine.

Upvotes: 4

Chris Pickford
Chris Pickford

Reputation: 8991

You can replace those two lines with a single line as follows:

else if(o is Enemy)
{
    ((Enemy)o).Update(time, player);
}

Upvotes: 4

Jodn
Jodn

Reputation: 324

You call the function in that way:

var a = ((Portal)o).Interact(ref player, player.Interact);

so the type of a will be the returned type of Interact, but in context of your code it won't matter much.

Upvotes: 3

Related Questions