【问题标题】:Create a new instance of a generic type at runtime without type checking在运行时创建一个泛型类型的新实例而不进行类型检查
【发布时间】:2017-12-04 05:46:15
【问题描述】:

下面的设计只是一个展示我的问题的模板。

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

问题是下次我添加一个新英雄时,我必须在 LevelUp 函数中添加另一个 if 语句,这会变得混乱。

我知道我可以使用 Activator.CreateInstance 创建一个新实例,但是有两个问题,1.所有对象都是不可变的。 2.构造函数中参数的数量和类型。

有人可以提出解决这个问题的方法吗?

编辑: 是的,cmets 部分的每个人都是正确的。我可以在 IHero 界面中添加 LevelUp 作为定义。

也许我选择了错误的概念来表达我的问题,但假设我想在外部处理 LevelUp,如模板中所示。有没有办法解决我唯一的问题,即创建一个 IHero 类型的新实例而无需进行类型检查?

【问题讨论】:

  • 为什么不在IHero中定义LevelUp?任何实现都会简单地返回this(当然我会质疑你是否真的需要在那里返回任何东西)。
  • 我认为您应该有一个实现 IHero 的类,并且您的两个英雄都应该继承该类。现在,您将重新定义每种新的子英雄类型中的英雄。但是它们都具有相同的属性(名称和级别),因此 iguess 将执行相同的操作。而且你的升级功能看起来很奇怪,因为你给了整个英雄并且它返回了一个英雄。在 IHero 中创建一个类似“LevelUp()”的方法,然后从那里开始。
  • @pijemcolu 是的,在这种情况下我可以。因为在 IHero 中将 LevelUp 作为定义是有意义的。但就像我说的,这只是一个简单的模板。我的业务逻辑要复杂得多(我无法透露),但问题是一样的。也许我所要求的不可行,但我需要与社区确认。
  • 一切皆有可能,但要付出理智的代价。你看过泛型吗? msdn.microsoft.com/en-us/library/ms379564(v=vs.80).aspx 。你的 LevelUp 看起来像 static T LevelUp<T>(T hero) where T : IHero { ... hero.Level++; ...}
  • @pijemcolu 您的建议与我在模板中显示的没有什么不同。我本可以简单地完成 Level++,但我喜欢保持我的对象不可变,因此 Level++ 不会工作。它们只能通过返回对象的新实例来修改。

标签: c# .net reflection interface solid-principles


【解决方案1】:

由于您的对象是不可变的,并且您希望将升级逻辑保留在每个英雄的特定类中,您最好将 LevelUp 方法添加到 IHero 接口。

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

在您的特定英雄类中,您可以像这样实现 LevelUp 方法。

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

您可以保留静态 leveup 函数以实现向后兼容性,但您应该将其重构掉。

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

【讨论】:

  • 猜猜你总是可以将对象序列化为二进制并反序列化它,然后增加级别......这将为你创建对象的新实例,无论它是什么类型。
  • 谢谢,我会调查的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多