投射不同的对象并在同一行中调用方法?

时间:2017-01-12 09:51:27

标签: c#

我有代码:

        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);
            }
        }

我不知道这样的事情是否可行?

我想在一行中完成。 这就是我的想法:

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

我知道这很愚蠢,但我想要类似的东西。将播放器作为参数的方法对于Enemy对象是唯一的。我必须解析才能打电话。

6 个答案:

答案 0 :(得分:7)

您可以简化循环(如果您使用C#6或更高版本):

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

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

对于C#5或更低版本,您应该使用:

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);
    }
}

在这种情况下,您的代码行数较少,但是您投了两次。

你只能投一次:

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);
    }
}

答案 1 :(得分:3)

试试这个:

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

如果您没有检查此对象的类型,请记住可能的Null Reference Exception。在你的代码中,一切都很好。

答案 2 :(得分:3)

您可以用一行代替这两行:

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

答案 3 :(得分:2)

你以这种方式调用函数:

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

因此,a的类型将是返回的Interact类型,但在代码的上下文中,它将无关紧要。

答案 4 :(得分:1)

要比其他回复更进一步,您可以使用visitor pattern

首先创建一个IVisitorClient和一个IVisitor界面。

interface IVisitorClient
{
    Accept(IVisitor visitor);
}

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

使您的不同对象实现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);
    }
...
}

然后构建一个实现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);
    }
}

最后,要更新对象,代码将如下所示。

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

答案 5 :(得分:0)

或者这样做以避免双重演绎...

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);
        }
    }
}