【问题标题】:Deep copying an array c# without serialization没有序列化的深度复制数组c#
【发布时间】:2013-02-28 09:46:13
【问题描述】:

基本上我的问题是我的MinMax 算法并没有真正按预期工作。

我需要将我的数组片段复制到newPieces,这样pieces 就不会在newPieces 被更改时发生变化。

这里是MinMax算法的摘录:

private int MinMax(
    int depth, Piece[] pieces, bool blacksTurn, 
    List<Move> Moves, Game game, int alpha, Move nextMove) {

    Piece[] newPieces=new Piece[24];
    Moves=Game.possibleMoves(pieces, blacksTurn, false);
    if(depth==0||Moves.Count==0) {
        return Evaluation(ref pieces);
    }

    int value;

    if(blacksTurn==true) {
        foreach(Move i in Moves) {
            newPieces=DeepCopy.ObjectExtensions.Copy(pieces);
            game.MovePiece(newPieces, blacksTurn, i.Moving, i.Destination, true);
            game.DisplayBoard(pieces);
            value=minMax(depth-1, newPieces, !blacksTurn, Moves, game, alpha, nextMove);

            if(alpha>value) {
                alpha=value;
                nextMove=i;
            }

    // ... 

这里是 Piece 类。

[StructLayout(LayoutKind.Sequential)]
public class Piece
{

    public CellReference Location;
    public bool isBlack { get; set; }
    public bool isKing { get; set; }
    private int Value { get; set; }
    public bool taken { get; set; }

    public Piece()
    {

    }

    public Piece(int i, bool isBlack, bool isKing, int CellsEast, int CellsNorth, bool taken)
    {
        this.Value = i;
        Location.CellsEast = CellsEast;
        Location.CellsNorth = CellsNorth;
        this.isBlack = isBlack;
        this.isKing = isKing;
        this.taken = taken;
    }
}

【问题讨论】:

  • Piece 是否足够复杂,足以保证类优于结构?根据这是什么游戏,您还可以选择根本不复制棋盘,而是记录信息,让您在评估后恢复移动。
  • 这个问题是关于“更高效的深拷贝”还是关于“更高效的 min-max”?
  • @DJKRAZE OP 专门要求 深拷贝MemberwiseClose 被记录为执行浅拷贝
  • 没错,彼得..我看了看我会删除我的评论
  • @500 我试着把它改成一个结构,一切似乎都坏了,所以我把它改回来了。另外,您建议如何记录所有信息?

标签: c# arrays deep-copy minmax


【解决方案1】:

我会在 Piece 类上实现 ICloneable ICloneable&lt;T&gt;

public interface ICloneable<T>
{
    T Clone();
}

pieces.Select(p =&gt; p.Clone()).ToArray(); 或仅使用 foreach 循环。

【讨论】:

  • 我建议只实现Clone 方法。实现ICloneable 接口没有任何好处,你甚至不能拥有“nice”返回类型,强制它为object
  • 或发ICloneable&lt;T&gt;
  • 当我这样做时它说它不能将类型 object[] 转换为 Piece[]。
  • 在 Piece 上实现 ICloneable 否则您需要将其转换为 pieces.Select(p =&gt; (Piece)p.Clone()).ToArray()
【解决方案2】:

将此属性添加到类/结构Piece

using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential)]
public class Piece {

代码如下

namespace DeepCopy {
    public static class ObjectExtensions {
        public static T[] Copy<T>(this T[] pieces) {
            return pieces.Select(x => {
                var handle=Marshal.AllocHGlobal(Marshal.SizeOf(typeof(T)));

                try {
                    Marshal.StructureToPtr(x, handle, false);
                    return (T)Marshal.PtrToStructure(handle, typeof(T));
                }
                finally {
                    Marshal.FreeHGlobal(handle);
                }
            }).ToArray();
        }
    }
}

我暂时将Piece.Value修改为public,供测试使用,已经用测试类测试过

public static partial class TestClass {
    public static void TestDeepCopy(Piece[] pieces) {
        Piece[] newPieces=new Piece[24];

        newPieces=DeepCopy.ObjectExtensions.Copy(pieces);

        newPieces[0].isKing=true;
        newPieces[0].Value=3;

        newPieces[1].isKing=true;
        newPieces[1].taken=true;
        newPieces[1].Value=4;

        Console.WriteLine("=== newPieces ===");
        foreach(var x in newPieces)
            Console.WriteLine(
                "x.isKing={0}; x.isBlack={1}; x.Value={2}",
                x.isKing, x.isBlack, x.Value
                );

        Console.WriteLine();
        Console.WriteLine("=== pieces ===");
        foreach(var x in pieces)
            Console.WriteLine(
                "x.isKing={0}; x.isBlack={1}; x.Value={2}",
                x.isKing, x.isBlack, x.Value
                );
    }

    public static void StartTest() {
        var pieceA=new Piece(1, false, false, 1, 1, false);
        var pieceB=new Piece(2, true, false, 1, 1, false);
        var pieces=new[] { pieceA, pieceB };
        TestDeepCopy(pieces);
    }
}

它有效。要执行测试,请调用

TestClass.StartTest();

【讨论】:

  • 还是不行……坦白说我很茫然,每一个副本似乎都有相同的结果,整个事情还是不行。
  • 哇...你做了什么?之前有什么问题..?我想发现
  • 好吧,它又搞砸了,但这次至少我知道问题出在哪里。这根本不是复制,实际上它隐藏在我的移动功能中。我实际上应该能够在那里找到问题。所以你的工作非常好,只是我搞砸了;D.
  • 可能需要更加小心AllocHGlobal。如果它在复制时爆炸,那么你就有内存泄漏。
【解决方案3】:

我认为this 可能有助于解决您的问题。它使用 ICloneable 接口让对象知道如何克隆自己。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-04-12
    • 1970-01-01
    • 1970-01-01
    • 2011-01-10
    • 2011-04-26
    • 2014-10-10
    • 2023-03-18
    • 1970-01-01
    相关资源
    最近更新 更多