在深度克隆时保留对静态类的引用

本文关键字:静态类 引用 保留 深度 | 更新日期: 2023-09-27 17:58:23

我正在开发用于管理任务的应用程序。每个任务都有自己的状态。每个状态都必须很容易分配(比如enum-task1.status.started)。每个状态都需要知道它的displayColor、名称等。所以它不能是简单的enum(我需要像--task1.stats.color这样的东西)。我不想用switch或很多if。Everithing必须非常快速(因为这将被迭代很多次),并且代码必须干净。

我做了什么:

public class BaseStatusType {
        public Color color;
        private string name;
        public BaseStatusType() { 
        }
        public override string ToString()
        {
           return "status" + name;
        }
        [Serializable]
        public class Untaken : BaseStatusType
        {
            public Untaken()
            {
                color = Appname.Core.App.Default.statusUntaken;
                name = "Untaken";
            }
        }

以及几种更像这样的任务类型(已执行、已开始、已结束、计费)。。

然后是状态类

    public class Status
        {
            public BaseStatusType Type;
            public Status()
            {
                this.Type = StatusType.statusUntaken;
            }
     }

以及最重要的静态部分。由于有了这个部分,它可以很容易地分配。

[Serializable]
    public static class StatusType {
        public static BaseStatusType.Untaken statusUntaken = new BaseStatusType.Untaken();
        public static BaseStatusType.Taken statusTaken = new BaseStatusType.Taken();
        public static BaseStatusType.Started statusStarted = new BaseStatusType.Started();
        public static BaseStatusType.Ended statusEnded = new BaseStatusType.Ended();
        public static BaseStatusType.Billing statusBilling = new BaseStatusType.Billing();            
    }

现在,所有状态都初始化一次,同时应用程序启动。并非每次都创建Status。在创建新任务时,会创建新的"状态",但它的"类型"仅被分配,而不是新建。

Status status1 = new Status();
            status1.Type = StatusType.statusEnded;
            Color somecolor = status1.Type.color;

现在来谈谈问题。一直工作得很好,直到我深度克隆对象任务。我的deepClone使用序列化/反序列化。这个问题可以这样描述:

            Task task1 = new Task();
            task1.Status.Type = StatusType.statusEnded;
            Task task2 = new Task();
            task2 = task1.DeepClone();
            if (task1.Status.Type == StatusType.statusEnded) { 
                //this returns true
            }
            if (task2.Status.Type == StatusType.statusEnded)
            {
                //this returns false
            }
            if (task2.Status.Type.ToString() == StatusType.statusEnded.ToString())
            {
                //this returns true
            }

这可能是因为它在DeepCopy时创建了自己的StatusType.statusEnd。但我不明白为什么。Status.Type不应该只保存对静态对象的引用吗?我很坚强。这就是为什么我不担心DeepCopy的原因。它应该只做引用的副本,而不是静态对象的副本。

那么,如果没有静态值的地址,什么会保留属性Status呢?

在深度克隆时保留对静态类的引用

您的Status.Type属性不是静态的。当您深度克隆对象时,会创建一个新实例并将其分配给克隆的实例。

你有两种方法:

  1. 修改DeepClone以查找现有实例并将其分配给克隆,而不是创建副本
  2. 实现IEquatable并覆盖常见的可疑项:GetHashCode、Equals、==和!=

#2的优点是,您不必确保您的状态对象是不可变的singleton(即,确保只有一个实例,并且在创建后永远不会修改它)。这是一个简单的编程模型,我怀疑它是否会对应用程序的性能产生丝毫影响。

以下是实现IEquatable接口的类的示例:

public class Identity : IEquatable<Identity>
{
    public Guid UniqueIdentifier { get; set; }
    public string Name { get; set; }
    public bool IsEmpty
    {
        get { return UniqueIdentifier == Guid.Empty; }
    }
    #region Construction
    public Identity()
    {
    }
    public Identity( Guid uniqueIdentifier, string name )
    {
        UniqueIdentifier = uniqueIdentifier;
        Name = name;
    } 
    #endregion
    public override string ToString()
    {
        return string.IsNullOrWhiteSpace( Name ) ? UniqueIdentifier.ToString() : Name;
    }
    #region IEquatable
    public override int GetHashCode()
    {
        return ToString().GetHashCode();
    }
    public override bool Equals( object obj )
    {
        return Equals( obj as Identity );
    }
    public static bool operator ==( Identity left, Identity right )
    {
        if( ReferenceEquals( null, left ) )
            return ReferenceEquals( null, right );
        return left.Equals( right );
    }
    public static bool operator !=( Identity left, Identity right )
    {
        if( ReferenceEquals( null, left ) )
            return !ReferenceEquals( null, right );
        return !left.Equals( right );
    }
    public bool Equals( Identity other )
    {
        if( ReferenceEquals( null, other ) )
            return false;
        return ToString() == other.ToString();
    }
    #endregion
}