将已实例化的对象作为新对象传递

时间:2015-10-29 12:31:04

标签: c#

这个问题可能听起来很奇怪,也请原谅我,因为我的程序流程可能都错了,但对我的情况有任何帮助都非常感谢!

我有一个名为EnemyFighter的类,它包含HP,攻击强度等所有信息。当程序启动时,它会将不同类型的敌人添加到列表中,如下所示:

// Build enemies
Enemies = new Dictionary<int, EnemyFighter>();

Enemies.Add(1, new EnemyFighter());
Enemies[1].Name = "Beaver";
Enemies[1].SetLevel(1);

Enemies.Add(2, new EnemyFighter());
Enemies[2].Name = "Unicorn";
Enemies[2].SetLevel(3);

然后我有敌人团体,所以你可以打多个敌人,也许两个海狸可以说:

// Enemy groups
EnemyGroups = new List<EnemyFighter[]>();

EnemyGroups.Add(new EnemyFighter[] { Enemies[1] }); // Beaver
EnemyGroups.Add(new EnemyFighter[] { Enemies[1], Enemies[1] }); // Beaver x2
EnemyGroups.Add(new EnemyFighter[] { Enemies[2] }); // Unicorn

但是当我去运行应用程序时,在攻击其中一个敌人时(当对抗两个海狸时)我意识到我正在攻击&#34;两者都是&#34;因为基本上都是&#34;海狸&#34;是同一个对象。

有人可以告诉我更好的方法来设置这种情况,我有一个对象的模板,但想要将它的唯一版本传递到列表中。像这样:

EnemyGroups.Add(new EnemyFighter[] { new Enemies[1], new Enemies[1] });

再次提前感谢任何帮助!

5 个答案:

答案 0 :(得分:2)

&#34;复制&#34;对象不是一件小事,在大多数情况下也是不可取的。

在这种情况下,最好的方法可能是做这样的事情:

public class EnemyPrototype
{
    public string Name  { get; set; }
    public int Level { get; set; }
}

public class EnemyProvider
{
    private Dictionary<string, EnemyPrototype> _prototypes = 
        new Dictionary<string, EnemyPrototype>();

    public void AddPrototype(string key, EnemyPrototype prototype)
    {
        _prototypes[key] = prototype;
    }

    public EnemyFighter GetEnemy(string key)
    {
        var prototype = _prototypes[key];

        var fighter = new EnemyFighter();
        fighter.Name = prototype.Name;
        fighter.SetLevel(prototype.Level);

        return fighter;
    }
}

现在你可以像这样创建你的新敌人原型(假设一个名为EnemyProvider的私人_provider实例成员 - 调整你的结构):

_provider = new EnemyProvider();
_provider.AddPrototype("Beaver", new EnemyPrototype {Name = "Beaver", Level = 1});

得到一个像这样的新人:

var enemy = _provider.GetEnemy("Beaver");

所以加入你的两个海狸就变成了:

EnemyGroups.Add(new EnemyFighter[] { _provider.GetEnemy("Beaver"),
                                     _provider.GetEnemy("Beaver") });

您还可以在EnemyProvider课程中添加一个方法,让您传递int并为您提供一系列敌人!

答案 1 :(得分:0)

因此,正如你所说,你攻击两者的原因是它们本质上是同一个对象。要解决此问题,您应该复制该对象。您可以创建一个这样的方法:

private EnemyFighter DuplicateEnemy(EnemyFighter original){
    var newEnemy = new EnemyFighter(){
        Name = original.Name
    };
    newEnemy.setLevel(original.Level);
    return newEnemy;
}

EnemyGroups.Add(new EnemyFighter[] { DuplicateEnemy(Enemies[1]) }); // Beaver
EnemyGroups.Add(new EnemyFighter[] { DuplicateEnemy(Enemies[1]), DuplicateEnemy(Enemies[1]) }); // Beaver x2
EnemyGroups.Add(new EnemyFighter[] { DuplicateEnemy(Enemies[2]) }); // Unicorn

这将返回具有相同值的新对象,您可以将其添加到列表中。

您还可以查看AutoMapper,它是一个用于复制对象的库,非常灵活,我以前在项目中使用它,发现它非常有用。 http://automapper.org/

答案 2 :(得分:0)

您可以使用MemberwiseClone()方法创建&#39;模板的浅表副本。将它添加到字典中时的对象。

https://msdn.microsoft.com/en-us/library/system.object.memberwiseclone.aspX

或者您可以实现一种方法来制作对象的深层副本。 上面的MemberwiseClone()链接中提供了创建浅拷贝和深拷贝的示例。

答案 3 :(得分:0)

正如您所注意到的,您在阵列中多次引用同一个对象。底线是你需要放入不同的新对象而不是相同的引用。

我推荐的做法是建造某种能够创造和回归新敌人的工厂。这样做的好处是能够从一般的敌人阵营中创造一个敌人,而不必担心你在克隆之前所做的任何修改。

public static class EnemyFactory
{
    public static EnemyFighter MakeBeaver()
    {
        var beaver = new EnemyFighter
        {
            Name = "Beaver",
            Level = 1
        };
        return beaver;
    }
}

然后使用工厂创建实例:

EnemyGroups.Add(new EnemyFighter[] { EnemyFactory.MakeBeaver(), EnemyFactory.MakeBeaver() }); // Beaver x2

答案 4 :(得分:0)

我认为你需要&#34;克隆&#34;你的初始对象。请查看MSDN中的ICloneable界面文档和示例:https://msdn.microsoft.com/en-us/library/system.icloneable.clone(v=vs.100).aspx