简体   繁体   中英

Create a new instance of a generic type at runtime without type checking

The following design is simply a template to show my problem.

public interface IHero
{
    string Name { get; }
    int Level { get; }
}
public interface IWarlock : IHero
{
    string MagicType { get; }
}
public interface IKnight : IHero
{
    string CommandHierarchy { get; } 
}
public class Warlock : IWarlock, IHero
{

    string IWarlock.MagicType { get { throw new NotImplementedException(); } }

    string IHero.Name { get { throw new NotImplementedException(); } }

    int IHero.Level { get { throw new NotImplementedException(); } }

    public Warlock(string name, int level, string magicType)
    {

    }
}
public class Knight : IKnight, IHero
{

    string IKnight.CommandHierarchy { get { throw new NotImplementedException(); } }

    string IHero.Name { get { throw new NotImplementedException(); } }

    int IHero.Level { get { throw new NotImplementedException(); } }

    public Knight(string name, int level, string commandHierarchy)
    {

    }
}
public class NullHero : IHero
{

    public string Name { get { return string.Empty } }

    public int Level { get { return -1; } }
}

class Program
{
    static void Main(string[] args)
    {

    }
    //Increments the hero's level.
    static IHero LevelUp(IHero hero)
    {
        if (hero is IWarlock)
            return new Warlock(hero.Name, hero.Level + 1, (hero as IWarlock).MagicType);
        else if (hero is IKnight)
            return new Knight(hero.Name, hero.Level + 1, (hero as IKnight).CommandHierarchy);
        else
            return new NullHero();
    }
}

The problem is that next time I add a new hero, I would have to add another if statement in the LevelUp function and this becomes messy.

I know I can use Activator.CreateInstance to create a new instance however there are two problems, 1. all objects are immutable. 2. number and type of parameters in the constructor.

Could anyone please suggest a solution to this problem?

EDIT: Yes, everyone in the comments section is correct. I can add LevelUp as a definition in the IHero interface.

Maybe I chose the wrong concept to convey my problem but let's assume that I wanted to handle LevelUp outside as shown in the template. Is there a way to tackle my only problem which is to create a new instance of type IHero without having to do type checking?

Since your objects are immutable and you want to keep your level up logic in the specific classes for each hero you would be best to add the LevelUp method to the IHero interface.

public interface IHero
{
    string Name { get; }
    int Level { get; }
    IHero LevelUp();
}

And in your specific hero classes you would implement the LevelUp method like so.

public IHero LevelUp()
{
    return new Warlock(this.Name, this.Level + 1, this.MagicType);
}

And you can keep your static leveup function for backwards compatibility, but you should refactor it away.

static IHero LevelUp(IHero hero)
{
    return hero.LevelUp();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM