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

时间:2013-02-09 16:14:14

标签: c# class static copy deep-copy

我正在开发app来管理任务。每个任务都有自己的状态。并且每个状态都必须易于分配(例如enum - task1.status = statuses.started)。并且每个状态都必须知道它的displayColor,name等。所以它不能简单枚举(我需要类似 - task1.status.color)。我不想使用开关或许多ifs。 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";

            }

        }

...和几种任务类型(Taken,Started,Ended,Billing)更像是这样..

然后是状态类

    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 status1 = new Status();
            status1.Type = StatusType.statusEnded;
            Color somecolor = status1.Type.color;

现在问题。 Everithing工作正常,直到我的deepClone对象任务。我的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.statusEnded。但我不明白为什么。 Status.Type不应仅包含对静态对象的引用吗?我这么做了。这就是为什么我不担心DeepCopy。它应该只制作引用的副本,而不是静态对象的副本。

那么如果没有静态值的地址,那么什么才能保存属性?

1 个答案:

答案 0 :(得分:0)

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

你有两种解决方法:

  1. 修改DeepClone以查找现有实例并将其分配给克隆而不是创建副本
  2. 实施IEquatable并覆盖通常的嫌疑人:GetHashCode,Equals,==和!=
  3. #2的优点是你不必确保你的状态对象是不可变的单例(即保证只有一个实例,并且一旦创建它就永远不会被修改)。这是一个简单的编程模型,我怀疑它会影响你的应用程序的性能。

    以下是实现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
    }