Home > database >  When is using IS and AS okay? How would you refactor this?
When is using IS and AS okay? How would you refactor this?

Time:09-01

I know that similar questions might have been asked before, but I am looking for an alternatvie solution to using IS, as I have read that IS is considered evil in the top-comment here.

So basically my Problem is that I have Abilities and Objects (Object A and Object B) that can use said abilities. However Object A lacks some data/information meaning it can only use some types of abilities (Ability A), while Object B has should be able to use all Abilities of type A and in addition some of type B.

For now I solved this the following way:

public abstract class BaseEffect
{
}
public abstract class GeneralEffect : BaseEffect
{
    public abstract void Trigger(int damage, float factor);
}
public class GeneralEffectTest : GeneralEffect
{
    public override void Trigger(int damage, float factor)
    {
        Console.WriteLine("Deal "   damage * factor   " damage");
    }
}
public abstract class PlayerEffect : BaseEffect
{
    public abstract void Trigger(int damage, string text, float factor);
}
public class PlayerEffectTest : PlayerEffect
{
    public override void Trigger(int damage, string playerOnlyInfo, float factor)
    {
        Console.WriteLine("Deal "   damage * factor   " "   text   "-damage");
    }
}

And basically a class that would be able to use both types of effects is the following:

public class TestClass
{
    public BaseEffect effect;

    public TestClass()
    {
        effect = new PlayerEffectTest();
    }

    public void Trigger()
    {
        if (effect is GeneralEffect)
        {
            ((GeneralEffect)effect).Trigger(2, 0.5f);
        }
        else if (effect is PlayerEffect)
        {
            ((PlayerEffect)effect).Trigger(2, "Fire", 0.2f);
        }
    }
}

A class that would be able to use just GeneralEffects would on the other hand just have a field defining a GeneralEffect.

I should maybe also note that for my actual use-case I would iterate through a List/Array of Effects.

Is there any way to avoid the "evil" IS here? How would you solve that issue?

CodePudding user response:

is isn't evil. Everything depends on its usage. In fact, is can be used since C# 7 in pattern matching which would allow you to write :

if (effect is GeneralEffect ge)
{
    ge.Trigger(2, 0.5f);
}
else if (effect is PlayerEffect pe)
{
    pe.Trigger(2, "Fire", 0.2f);
}

An even better option would be to use pattern matching with switch :

switch(effect)
{
    case PlayerEffect pe:
        pe.Trigger(2, "Fire", 0.2f);
        break;
    case GeneralEffect ge:
        ge.Trigger(2, 0.5f);
        break;
}

Pattern matching is far more powerful than this, as you can match on properties, not just types. It's also possible to add guard clauses:

switch(effect)
{
    case PlayerEffect pe when player.Ammo>0:
        pe.Trigger(2, "Fire", 0.2f);
        break;
    case PlayerEffect pe:
        pe.Trigger(0, "Click", 0.0f);
        break;
    case GeneralEffect ge:
        ge.Trigger(2, 0.5f);
        break;
}
  •  Tags:  
  • c#
  • Related